home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / window.c < prev   
Encoding:
C/C++ Source or Header  |  2001-09-15  |  108.6 KB  |  4,812 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read a list of people who contributed.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. #include "vim.h"
  11.  
  12. #ifdef HAVE_FCNTL_H
  13. # include <fcntl.h>        /* for chdir() */
  14. #endif
  15.  
  16. static int path_is_url __ARGS((char_u *p));
  17. #if defined(FEAT_WINDOWS) || defined(PROTO)
  18. static int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
  19. static int win_comp_pos __ARGS((void));
  20. static void frame_comp_pos __ARGS((frame_T *topfrp, int *row, int *col));
  21. static void frame_setheight __ARGS((frame_T *curfrp, int height));
  22. #ifdef FEAT_VERTSPLIT
  23. static void frame_setwidth __ARGS((frame_T *curfrp, int width));
  24. #endif
  25. static void win_exchange __ARGS((long));
  26. static void win_rotate __ARGS((int, int));
  27. static void win_totop __ARGS((int size, int flags));
  28. static void win_equal_rec __ARGS((win_T *next_curwin, frame_T *topfr, int dir, int col, int row, int width, int height));
  29. static win_T *winframe_remove __ARGS((win_T *win, int *dirp));
  30. static frame_T *win_altframe __ARGS((win_T *win));
  31. static win_T *frame2win __ARGS((frame_T *frp));
  32. static int frame_has_win __ARGS((frame_T *frp, win_T *wp));
  33. static void frame_new_height __ARGS((frame_T *topfrp, int height, int topfirst));
  34. #ifdef FEAT_VERTSPLIT
  35. static void frame_add_statusline __ARGS((frame_T *frp));
  36. static void frame_new_width __ARGS((frame_T *topfrp, int width, int leftfirst));
  37. static void frame_add_vsep __ARGS((frame_T *frp));
  38. static int frame_minwidth __ARGS((frame_T *topfrp, win_T *next_curwin));
  39. static void frame_fix_width __ARGS((win_T *wp));
  40. #endif
  41. static void frame_fix_height __ARGS((win_T *wp));
  42. static int frame_minheight __ARGS((frame_T *topfrp, win_T *next_curwin));
  43. static void win_enter_ext __ARGS((win_T *wp, int undo_sync, int no_curwin));
  44. static void win_free __ARGS((win_T *wp));
  45. static void win_append __ARGS((win_T *, win_T *));
  46. static void win_remove __ARGS((win_T *));
  47. static void frame_append __ARGS((frame_T *after, frame_T *frp));
  48. static void frame_insert __ARGS((frame_T *before, frame_T *frp));
  49. static void frame_remove __ARGS((frame_T *frp));
  50. #ifdef FEAT_VERTSPLIT
  51. static void win_new_width __ARGS((win_T *wp, int width));
  52. static int win_minheight __ARGS((win_T *wp));
  53. static void win_goto_ver __ARGS((int up, long count));
  54. static void win_goto_hor __ARGS((int left, long count));
  55. #endif
  56. static void frame_add_height __ARGS((frame_T *frp, int n));
  57. static void last_status_rec __ARGS((frame_T *fr, int statusline));
  58.  
  59. static void make_snapshot __ARGS((void));
  60. static void make_snapshot_rec __ARGS((frame_T *fr, frame_T **frp));
  61. static void clear_snapshot __ARGS((void));
  62. static void clear_snapshot_rec __ARGS((frame_T *fr));
  63. static void restore_snapshot __ARGS((int close_curwin));
  64. static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
  65. static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
  66.  
  67. static win_T    *prevwin = NULL;    /* previous window */
  68. #endif /* FEAT_WINDOWS */
  69. static void win_setheight_win __ARGS((int height, win_T *win));
  70. static win_T *win_alloc __ARGS((win_T *after));
  71. static void win_new_height __ARGS((win_T *, int));
  72.  
  73. #define URL_SLASH    1        /* path_is_url() has found "://" */
  74. #define URL_BACKSLASH    2        /* path_is_url() has found ":\\" */
  75.  
  76. #define NOWIN        (win_T *)-1    /* non-exisiting window */
  77.  
  78. #if defined(FEAT_WINDOWS) || defined(PROTO)
  79. /*
  80.  * all CTRL-W window commands are handled here, called from normal_cmd().
  81.  */
  82.     void
  83. do_window(nchar, Prenum)
  84.     int        nchar;
  85.     long    Prenum;
  86. {
  87.     long    Prenum1;
  88.     win_T    *wp;
  89.     int        xchar;
  90. #if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
  91.     char_u    *ptr;
  92. #endif
  93. #ifdef FEAT_FIND_ID
  94.     int        type = FIND_DEFINE;
  95.     int        len;
  96. #endif
  97.  
  98.     if (Prenum == 0)
  99.     Prenum1 = 1;
  100.     else
  101.     Prenum1 = Prenum;
  102.  
  103. #ifdef FEAT_CMDWIN
  104. # define CHECK_CMDWIN if (cmdwin_type != 0) { EMSG(_(e_cmdwin)); break; }
  105. #else
  106. # define CHECK_CMDWIN
  107. #endif
  108.  
  109.     switch (nchar)
  110.     {
  111. /* split current window in two parts, horizontally */
  112.     case 'S':
  113.     case Ctrl_S:
  114.     case 's':
  115.         CHECK_CMDWIN
  116. #ifdef FEAT_VISUAL
  117.         reset_VIsual_and_resel();    /* stop Visual mode */
  118. #endif
  119. #ifdef FEAT_GUI
  120.         need_mouse_correct = TRUE;
  121. #endif
  122.         win_split((int)Prenum, 0);
  123.         break;
  124.  
  125. #ifdef FEAT_VERTSPLIT
  126. /* split current window in two parts, vertically */
  127.     case Ctrl_V:
  128.     case 'v':
  129.         CHECK_CMDWIN
  130. #ifdef FEAT_VISUAL
  131.         reset_VIsual_and_resel();    /* stop Visual mode */
  132. #endif
  133. #ifdef FEAT_GUI
  134.         need_mouse_correct = TRUE;
  135. #endif
  136.         win_split((int)Prenum, WSP_VERT);
  137.         break;
  138. #endif
  139.  
  140. /* split current window and edit alternate file */
  141.     case Ctrl_HAT:
  142.     case '^':
  143.         CHECK_CMDWIN
  144. #ifdef FEAT_VISUAL
  145.         reset_VIsual_and_resel();    /* stop Visual mode */
  146. #endif
  147.         stuffReadbuff((char_u *)":split #");
  148.         if (Prenum)
  149.             stuffnumReadbuff(Prenum);    /* buffer number */
  150.         stuffcharReadbuff('\n');
  151.         break;
  152.  
  153. /* open new window */
  154.     case Ctrl_N:
  155.     case 'n':
  156.         CHECK_CMDWIN
  157. #ifdef FEAT_VISUAL
  158.         reset_VIsual_and_resel();    /* stop Visual mode */
  159. #endif
  160.         stuffcharReadbuff(':');
  161.         if (Prenum)
  162.             stuffnumReadbuff(Prenum);    /* window height */
  163.         stuffReadbuff((char_u *)"new\n");
  164.         break;
  165.  
  166. /* quit current window */
  167.     case Ctrl_Q:
  168.     case 'q':
  169. #ifdef FEAT_VISUAL
  170.         reset_VIsual_and_resel();    /* stop Visual mode */
  171. #endif
  172.         stuffReadbuff((char_u *)":quit\n");
  173.         break;
  174.  
  175. /* close current window */
  176.     case Ctrl_C:
  177.     case 'c':
  178. #ifdef FEAT_VISUAL
  179.         reset_VIsual_and_resel();    /* stop Visual mode */
  180. #endif
  181.         stuffReadbuff((char_u *)":close\n");
  182.         break;
  183.  
  184. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  185. /* close preview window */
  186.     case Ctrl_Z:
  187.     case 'z':
  188.         CHECK_CMDWIN
  189. #ifdef FEAT_VISUAL
  190.         reset_VIsual_and_resel();    /* stop Visual mode */
  191. #endif
  192.         stuffReadbuff((char_u *)":pclose\n");
  193.         break;
  194.  
  195. /* cursor to preview window */
  196.     case 'P':
  197.         for (wp = firstwin; wp != NULL; wp = wp->w_next)
  198.             if (wp->w_p_pvw)
  199.             break;
  200.         if (wp == NULL)
  201.             EMSG(_("E441: There is no preview window"));
  202.         else
  203.             win_goto(wp);
  204.         break;
  205. #endif
  206.  
  207. /* close all but current window */
  208.     case Ctrl_O:
  209.     case 'o':
  210.         CHECK_CMDWIN
  211. #ifdef FEAT_VISUAL
  212.         reset_VIsual_and_resel();    /* stop Visual mode */
  213. #endif
  214.         stuffReadbuff((char_u *)":only\n");
  215.         break;
  216.  
  217. /* cursor to next window with wrap around */
  218.     case Ctrl_W:
  219.     case 'w':
  220. /* cursor to previous window with wrap around */
  221.     case 'W':
  222.         CHECK_CMDWIN
  223.         if (lastwin == firstwin)    /* just one window */
  224.             beep_flush();
  225.         else
  226.         {
  227.             if (Prenum)            /* go to specified window */
  228.             {
  229.             for (wp = firstwin; --Prenum > 0; )
  230.             {
  231.                 if (wp->w_next == NULL)
  232.                 break;
  233.                 else
  234.                 wp = wp->w_next;
  235.             }
  236.             }
  237.             else
  238.             {
  239.             if (nchar == 'W')        /* go to previous window */
  240.             {
  241.                 wp = curwin->w_prev;
  242.                 if (wp == NULL)
  243.                 wp = lastwin;        /* wrap around */
  244.             }
  245.             else                /* go to next window */
  246.             {
  247.                 wp = curwin->w_next;
  248.                 if (wp == NULL)
  249.                 wp = firstwin;        /* wrap around */
  250.             }
  251.             }
  252.             win_goto(wp);
  253.         }
  254.         break;
  255.  
  256. /* cursor to window below */
  257.     case 'j':
  258.     case K_DOWN:
  259.     case Ctrl_J:
  260.         CHECK_CMDWIN
  261. #ifdef FEAT_VERTSPLIT
  262.         win_goto_ver(FALSE, Prenum1);
  263. #else
  264.         for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
  265.                                 wp = wp->w_next)
  266.             ;
  267.         win_goto(wp);
  268. #endif
  269.         break;
  270.  
  271. /* cursor to window above */
  272.     case 'k':
  273.     case K_UP:
  274.     case Ctrl_K:
  275.         CHECK_CMDWIN
  276. #ifdef FEAT_VERTSPLIT
  277.         win_goto_ver(TRUE, Prenum1);
  278. #else
  279.         for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
  280.                                 wp = wp->w_prev)
  281.             ;
  282.         win_goto(wp);
  283. #endif
  284.         break;
  285.  
  286. #ifdef FEAT_VERTSPLIT
  287. /* cursor to left window */
  288.     case 'h':
  289.     case K_LEFT:
  290.     case Ctrl_H:
  291.     case K_BS:
  292.         CHECK_CMDWIN
  293.         win_goto_hor(TRUE, Prenum1);
  294.         break;
  295.  
  296. /* cursor to right window */
  297.     case 'l':
  298.     case K_RIGHT:
  299.     case Ctrl_L:
  300.         CHECK_CMDWIN
  301.         win_goto_hor(FALSE, Prenum1);
  302.         break;
  303. #endif
  304.  
  305. /* cursor to top-left window */
  306.     case 't':
  307.     case Ctrl_T:
  308.         win_goto(firstwin);
  309.         break;
  310.  
  311. /* cursor to bottom-right window */
  312.     case 'b':
  313.     case Ctrl_B:
  314.         win_goto(lastwin);
  315.         break;
  316.  
  317. /* cursor to last accessed (previous) window */
  318.     case 'p':
  319.     case Ctrl_P:
  320.         if (prevwin == NULL)
  321.             beep_flush();
  322.         else
  323.             win_goto(prevwin);
  324.         break;
  325.  
  326. /* exchange current and next window */
  327.     case 'x':
  328.     case Ctrl_X:
  329.         CHECK_CMDWIN
  330.         win_exchange(Prenum);
  331.         break;
  332.  
  333. /* rotate windows downwards */
  334.     case Ctrl_R:
  335.     case 'r':
  336.         CHECK_CMDWIN
  337. #ifdef FEAT_VISUAL
  338.         reset_VIsual_and_resel();    /* stop Visual mode */
  339. #endif
  340.         win_rotate(FALSE, (int)Prenum1);    /* downwards */
  341.         break;
  342.  
  343. /* rotate windows upwards */
  344.     case 'R':
  345.         CHECK_CMDWIN
  346. #ifdef FEAT_VISUAL
  347.         reset_VIsual_and_resel();    /* stop Visual mode */
  348. #endif
  349.         win_rotate(TRUE, (int)Prenum1);        /* upwards */
  350.         break;
  351.  
  352. /* move window to the very top/bottom/left/right */
  353.     case 'K':
  354.     case 'J':
  355. #ifdef FEAT_VERTSPLIT
  356.     case 'H':
  357.     case 'L':
  358. #endif
  359.         CHECK_CMDWIN
  360.         win_totop((int)Prenum,
  361.             ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
  362.             | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
  363.         break;
  364.  
  365. /* make all windows the same height */
  366.     case '=':
  367. #ifdef FEAT_GUI
  368.         need_mouse_correct = TRUE;
  369. #endif
  370.         win_equal(NULL, 0);
  371.         break;
  372.  
  373. /* increase current window height */
  374.     case '+':
  375. #ifdef FEAT_GUI
  376.         need_mouse_correct = TRUE;
  377. #endif
  378.         win_setheight(curwin->w_height + (int)Prenum1);
  379.         break;
  380.  
  381. /* decrease current window height */
  382.     case '-':
  383. #ifdef FEAT_GUI
  384.         need_mouse_correct = TRUE;
  385. #endif
  386.         win_setheight(curwin->w_height - (int)Prenum1);
  387.         break;
  388.  
  389. /* set current window height */
  390.     case Ctrl__:
  391.     case '_':
  392. #ifdef FEAT_GUI
  393.         need_mouse_correct = TRUE;
  394. #endif
  395.         win_setheight(Prenum ? (int)Prenum : 9999);
  396.         break;
  397.  
  398. #ifdef FEAT_VERTSPLIT
  399. /* increase current window width */
  400.     case '>':
  401. #ifdef FEAT_GUI
  402.         need_mouse_correct = TRUE;
  403. #endif
  404.         win_setwidth(curwin->w_width + (int)Prenum1);
  405.         break;
  406.  
  407. /* decrease current window width */
  408.     case '<':
  409. #ifdef FEAT_GUI
  410.         need_mouse_correct = TRUE;
  411. #endif
  412.         win_setwidth(curwin->w_width - (int)Prenum1);
  413.         break;
  414.  
  415. /* set current window width */
  416.     case '|':
  417. #ifdef FEAT_GUI
  418.         need_mouse_correct = TRUE;
  419. #endif
  420.         win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
  421.         break;
  422. #endif
  423.  
  424. /* jump to tag and split window if tag exists (in preview window) */
  425. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  426.     case '}':
  427.         CHECK_CMDWIN
  428.         if (Prenum)
  429.             g_do_tagpreview = Prenum;
  430.         else
  431.             g_do_tagpreview = p_pvh;
  432.         /*FALLTHROUGH*/
  433. #endif
  434.     case ']':
  435.     case Ctrl_RSB:
  436.         CHECK_CMDWIN
  437. #ifdef FEAT_VISUAL
  438.         reset_VIsual_and_resel();    /* stop Visual mode */
  439. #endif
  440.         if (Prenum)
  441.             postponed_split = Prenum;
  442.         else
  443.             postponed_split = -1;
  444.         stuffcharReadbuff(Ctrl_RSB);
  445.         break;
  446.  
  447. #ifdef FEAT_SEARCHPATH
  448. /* edit file name under cursor in a new window */
  449.     case 'f':
  450.     case Ctrl_F:
  451.         CHECK_CMDWIN
  452. #ifdef FEAT_VISUAL
  453.         reset_VIsual_and_resel();    /* stop Visual mode */
  454. #endif
  455.         ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP,
  456.                                      Prenum1);
  457.         if (ptr != NULL)
  458.         {
  459. #ifdef FEAT_GUI
  460.             need_mouse_correct = TRUE;
  461. #endif
  462.             setpcmark();
  463.             if (win_split(0, 0) == OK)
  464.             (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
  465.                                    ECMD_HIDE);
  466.             vim_free(ptr);
  467.         }
  468.         break;
  469. #endif
  470.  
  471. #ifdef FEAT_FIND_ID
  472. /* Go to the first occurence of the identifier under cursor along path in a
  473.  * new window -- webb
  474.  */
  475.     case 'i':                /* Go to any match */
  476.     case Ctrl_I:
  477.         type = FIND_ANY;
  478.         /* FALLTHROUGH */
  479.     case 'd':                /* Go to definition, using 'define' */
  480.     case Ctrl_D:
  481.         CHECK_CMDWIN
  482.         if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
  483.             break;
  484.         find_pattern_in_path(ptr, 0, len, TRUE,
  485.             Prenum == 0 ? TRUE : FALSE, type,
  486.             Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
  487.         curwin->w_set_curswant = TRUE;
  488.         break;
  489. #endif
  490.  
  491. /* CTRL-W g  extended commands */
  492.     case 'g':
  493.     case Ctrl_G:
  494.         CHECK_CMDWIN
  495. #ifdef USE_ON_FLY_SCROLL
  496.         dont_scroll = TRUE;        /* disallow scrolling here */
  497. #endif
  498.         ++no_mapping;
  499.         ++allow_keys;   /* no mapping for xchar, but allow key codes */
  500.         xchar = safe_vgetc();
  501. #ifdef FEAT_LANGMAP
  502.         LANGMAP_ADJUST(xchar, TRUE);
  503. #endif
  504.         --no_mapping;
  505.         --allow_keys;
  506. #ifdef FEAT_CMDL_INFO
  507.         (void)add_to_showcmd(xchar);
  508. #endif
  509.         switch (xchar)
  510.         {
  511. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  512.             case '}':
  513.             xchar = Ctrl_RSB;
  514.             if (Prenum)
  515.                 g_do_tagpreview = Prenum;
  516.             else
  517.                 g_do_tagpreview = p_pvh;
  518.             /*FALLTHROUGH*/
  519. #endif
  520.             case ']':
  521.             case Ctrl_RSB:
  522. #ifdef FEAT_VISUAL
  523.             reset_VIsual_and_resel();    /* stop Visual mode */
  524. #endif
  525.             if (Prenum)
  526.                 postponed_split = Prenum;
  527.             else
  528.                 postponed_split = -1;
  529.             stuffcharReadbuff('g');
  530.             stuffcharReadbuff(xchar);
  531.             break;
  532.  
  533.             default:
  534.             beep_flush();
  535.             break;
  536.         }
  537.         break;
  538.  
  539.     default:    beep_flush();
  540.         break;
  541.     }
  542. }
  543.  
  544. /*
  545.  * split the current window, implements CTRL-W s and :split
  546.  *
  547.  * "size" is the height or width for the new window, 0 to use half of current
  548.  * height or width.
  549.  *
  550.  * "flags":
  551.  * WSP_ROOM: require enough room for new window
  552.  * WSP_VERT: vertical split.
  553.  * WSP_TOP:  open window at the top-left of the shell (help window).
  554.  * WSP_BOT:  open window at the bottom-right of the shell (quickfix window).
  555.  * WSP_HELP: creating the help window, keep layout snapshot
  556.  *
  557.  * return FAIL for failure, OK otherwise
  558.  */
  559.     int
  560. win_split(size, flags)
  561.     int        size;
  562.     int        flags;
  563. {
  564.     /* Add flags from ":vertical", ":topleft" and ":botright". */
  565.     flags |= cmdmod.split;
  566.     if ((flags & WSP_TOP) && (flags & WSP_BOT))
  567.     {
  568.     EMSG(_("E442: Can't split topleft and botright at the same time"));
  569.     return FAIL;
  570.     }
  571.  
  572.     /* When creating the help window make a snapshot of the window layout.
  573.      * Otherwise clear the snapshot, it's now invalid. */
  574.     if (flags & WSP_HELP)
  575.     make_snapshot();
  576.     else
  577.     clear_snapshot();
  578.  
  579.     return win_split_ins(size, flags, NULL, 0);
  580. }
  581.  
  582. /*
  583.  * When "newwin" is NULL: split a window in two.
  584.  * When "newwin" is not NULL: insert this window at the far
  585.  * top/left/right/bottom.
  586.  * return FAIL for failure, OK otherwise
  587.  */
  588.     static int
  589. win_split_ins(size, flags, newwin, dir)
  590.     int        size;
  591.     int        flags;
  592.     win_T    *newwin;
  593.     int        dir;
  594. {
  595.     win_T    *wp = newwin;
  596.     win_T    *oldwin;
  597.     int        new_size = size;
  598.     int        i;
  599.     int        need_status = 0;
  600.     int        do_equal = FALSE;
  601.     int        needed;
  602.     int        available;
  603.     int        oldwin_height = 0;
  604.     int        layout;
  605.     frame_T    *frp, *curfrp;
  606.     int        before;
  607.  
  608.     if (flags & WSP_TOP)
  609.     oldwin = firstwin;
  610.     else if (flags & WSP_BOT)
  611.     oldwin = lastwin;
  612.     else
  613.     oldwin = curwin;
  614.  
  615.     /* add a status line when p_ls == 1 and splitting the first window */
  616.     if (lastwin == firstwin && p_ls == 1 && oldwin->w_status_height == 0)
  617.     {
  618.     if (oldwin->w_height <= p_wmh && newwin == NULL)
  619.     {
  620.         EMSG(_(e_noroom));
  621.         return FAIL;
  622.     }
  623.     need_status = STATUS_HEIGHT;
  624.     }
  625.  
  626. #ifdef FEAT_VERTSPLIT
  627.     if (flags & WSP_VERT)
  628.     {
  629.     layout = FR_ROW;
  630.     do_equal = (p_ea && new_size == 0 && *p_ead != 'v');
  631.  
  632.     /*
  633.      * Check if we are able to split the current window and compute its
  634.      * width.
  635.      */
  636.     needed = p_wmw + 1;
  637.     if (flags & WSP_ROOM)
  638.         needed += p_wiw - p_wmw;
  639.     if (p_ea || (flags & (WSP_BOT | WSP_TOP)))
  640.     {
  641.         available = topframe->fr_width;
  642.         needed += frame_minwidth(topframe, NULL);
  643.     }
  644.     else
  645.         available = oldwin->w_width;
  646.     if (available < needed && newwin == NULL)
  647.     {
  648.         EMSG(_(e_noroom));
  649.         return FAIL;
  650.     }
  651.     if (new_size == 0)
  652.         new_size = oldwin->w_width / 2;
  653.     if (new_size > oldwin->w_width - p_wmw - 1)
  654.         new_size = oldwin->w_width - p_wmw - 1;
  655.     if (new_size < p_wmw)
  656.         new_size = p_wmw;
  657.  
  658.     /* if it doesn't fit in the current window, need win_equal() */
  659.     if (oldwin->w_width - new_size - 1 < p_wmw)
  660.         do_equal = TRUE;
  661.     }
  662.     else
  663. #endif
  664.     {
  665.     layout = FR_COL;
  666.     do_equal = (p_ea && new_size == 0
  667. #ifdef FEAT_VERTSPLIT
  668.         && *p_ead != 'h'
  669. #endif
  670.         );
  671.  
  672.     /*
  673.      * Check if we are able to split the current window and compute its
  674.      * height.
  675.      */
  676.     needed = p_wmh + STATUS_HEIGHT + need_status;
  677.     if (flags & WSP_ROOM)
  678.         needed += p_wh - p_wmh;
  679.     if (p_ea || (flags & (WSP_BOT | WSP_TOP)))
  680.     {
  681.         available = topframe->fr_height;
  682.         needed += frame_minheight(topframe, NULL);
  683.     }
  684.     else
  685.     {
  686.         available = oldwin->w_height;
  687.         needed += p_wmh;
  688.     }
  689.     if (available < needed && newwin == NULL)
  690.     {
  691.         EMSG(_(e_noroom));
  692.         return FAIL;
  693.     }
  694.     oldwin_height = oldwin->w_height;
  695.     if (need_status)
  696.     {
  697.         oldwin->w_status_height = STATUS_HEIGHT;
  698.         oldwin_height -= STATUS_HEIGHT;
  699.     }
  700.     if (new_size == 0)
  701.         new_size = oldwin_height / 2;
  702.  
  703.     if (new_size > oldwin_height - p_wmh - STATUS_HEIGHT)
  704.         new_size = oldwin_height - p_wmh - STATUS_HEIGHT;
  705.     if (new_size < p_wmh)
  706.         new_size = p_wmh;
  707.  
  708.     /* if it doesn't fit in the current window, need win_equal() */
  709.     if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
  710.         do_equal = TRUE;
  711. #ifdef FEAT_QUICKFIX
  712.     /* We don't like to take lines for the new window from a quickfix
  713.      * or preview window.  Take them from a window above or below
  714.      * instead, if possible. */
  715.     if (bt_quickfix(oldwin->w_buffer) || oldwin->w_p_pvw)
  716.     {
  717.         win_setheight_win(oldwin->w_height + new_size, oldwin);
  718.         oldwin_height = oldwin->w_height;
  719.         if (need_status)
  720.         oldwin_height -= STATUS_HEIGHT;
  721.     }
  722. #endif
  723.     }
  724.  
  725.     /*
  726.      * allocate new window structure and link it in the window list
  727.      */
  728.     if ((flags & WSP_TOP) == 0
  729.         && ((flags & WSP_BOT)
  730.         || (flags & WSP_BELOW)
  731.         || (!(flags & WSP_ABOVE)
  732.             && (
  733. #ifdef FEAT_VERTSPLIT
  734.             (flags & WSP_VERT) ? p_spr :
  735. #endif
  736.             p_sb))))
  737.     {
  738.     /* new window below/right of current one */
  739.     if (newwin == NULL)
  740.         wp = win_alloc(oldwin);
  741.     else
  742.         win_append(oldwin, wp);
  743.     }
  744.     else
  745.     {
  746.     if (newwin == NULL)
  747.         wp = win_alloc(oldwin->w_prev);
  748.     else
  749.         win_append(oldwin->w_prev, wp);
  750.     }
  751.  
  752.     if (newwin == NULL)
  753.     {
  754.     if (wp == NULL)
  755.         return FAIL;
  756.  
  757.     /*
  758.      * make the contents of the new window the same as the current one
  759.      */
  760.     wp->w_buffer = curbuf;
  761.     curbuf->b_nwindows++;
  762.     wp->w_cursor = curwin->w_cursor;
  763.     wp->w_valid = 0;
  764.     wp->w_curswant = curwin->w_curswant;
  765.     wp->w_set_curswant = curwin->w_set_curswant;
  766.     wp->w_topline = curwin->w_topline;
  767. #ifdef FEAT_DIFF
  768.     wp->w_topfill = curwin->w_topfill;
  769. #endif
  770.     wp->w_leftcol = curwin->w_leftcol;
  771.     wp->w_pcmark = curwin->w_pcmark;
  772.     wp->w_prev_pcmark = curwin->w_prev_pcmark;
  773.     wp->w_alt_fnum = curwin->w_alt_fnum;
  774.     wp->w_fraction = curwin->w_fraction;
  775.     wp->w_prev_fraction_row = curwin->w_prev_fraction_row;
  776. #ifdef FEAT_JUMPLIST
  777.     copy_jumplist(curwin, wp);
  778. #endif
  779.     if (curwin->w_localdir != NULL)
  780.         wp->w_localdir = vim_strsave(curwin->w_localdir);
  781.  
  782.     /* Use the same argument list. */
  783.     wp->w_alist = curwin->w_alist;
  784.     ++wp->w_alist->al_refcount;
  785.     wp->w_arg_idx = curwin->w_arg_idx;
  786.  
  787.     /*
  788.      * copy tagstack and options from existing window
  789.      */
  790.     for (i = 0; i < curwin->w_tagstacklen; i++)
  791.     {
  792.         wp->w_tagstack[i] = curwin->w_tagstack[i];
  793.         if (wp->w_tagstack[i].tagname != NULL)
  794.         wp->w_tagstack[i].tagname =
  795.                        vim_strsave(wp->w_tagstack[i].tagname);
  796.     }
  797.     wp->w_tagstackidx = curwin->w_tagstackidx;
  798.     wp->w_tagstacklen = curwin->w_tagstacklen;
  799.     win_copy_options(curwin, wp);
  800. #ifdef FEAT_FOLDING
  801.     copyFoldingState(curwin, wp);
  802. #endif
  803.     }
  804.  
  805.     /*
  806.      * Reorganise the tree of frames to insert the new window.
  807.      */
  808.     if (flags & (WSP_TOP | WSP_BOT))
  809.     {
  810. #ifdef FEAT_VERTSPLIT
  811.     if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
  812.         || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
  813. #else
  814.     if (topframe->fr_layout == FR_COL)
  815. #endif
  816.     {
  817.         curfrp = topframe->fr_child;
  818.         if (flags & WSP_BOT)
  819.         while (curfrp->fr_next != NULL)
  820.             curfrp = curfrp->fr_next;
  821.     }
  822.     else
  823.         curfrp = topframe;
  824.     before = (flags & WSP_TOP);
  825.     }
  826.     else
  827.     {
  828.     curfrp = oldwin->w_frame;
  829.     if (flags & WSP_BELOW)
  830.         before = FALSE;
  831.     else if (flags & WSP_ABOVE)
  832.         before = TRUE;
  833.     else
  834. #ifdef FEAT_VERTSPLIT
  835.     if (flags & WSP_VERT)
  836.         before = !p_spr;
  837.     else
  838. #endif
  839.         before = !p_sb;
  840.     }
  841.     if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
  842.     {
  843.     /* Need to create a new frame in the tree to make a branch. */
  844.     frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
  845.     *frp = *curfrp;
  846.     curfrp->fr_layout = layout;
  847.     frp->fr_parent = curfrp;
  848.     frp->fr_next = NULL;
  849.     frp->fr_prev = NULL;
  850.     curfrp->fr_child = frp;
  851.     curfrp->fr_win = NULL;
  852.     curfrp = frp;
  853.     if (frp->fr_win != NULL)
  854.         oldwin->w_frame = frp;
  855.     else
  856.         for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
  857.         frp->fr_parent = curfrp;
  858.     }
  859.  
  860.     if (newwin == NULL)
  861.     {
  862.     /* Create a frame for the new window. */
  863.     frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
  864.     frp->fr_layout = FR_LEAF;
  865.     frp->fr_win = wp;
  866.     wp->w_frame = frp;
  867.     }
  868.     else
  869.     frp = newwin->w_frame;
  870.     frp->fr_parent = curfrp->fr_parent;
  871.  
  872.     /* Insert the new frame at the right place in the frame list. */
  873.     if (before)
  874.     frame_insert(curfrp, frp);
  875.     else
  876.     frame_append(curfrp, frp);
  877.  
  878. #ifdef FEAT_VERTSPLIT
  879.     if (flags & WSP_VERT)
  880.     {
  881.     wp->w_p_scr = curwin->w_p_scr;
  882.     if (need_status)
  883.     {
  884.         --oldwin->w_height;
  885.         oldwin->w_status_height = need_status;
  886.     }
  887.     if (flags & (WSP_TOP | WSP_BOT))
  888.     {
  889.         /* set height and row of new window to full height */
  890.         wp->w_winrow = 0;
  891.         wp->w_height = curfrp->fr_height - (p_ls > 0);
  892.         wp->w_status_height = (p_ls > 0);
  893.     }
  894.     else
  895.     {
  896.         /* height and row of new window is same as current window */
  897.         wp->w_winrow = oldwin->w_winrow;
  898.         wp->w_height = oldwin->w_height;
  899.         wp->w_status_height = oldwin->w_status_height;
  900.     }
  901.     frp->fr_height = curfrp->fr_height;
  902.  
  903.     /* "new_size" of the current window goes to the new window, use
  904.      * one column for the vertical separator */
  905.     wp->w_width = new_size;
  906.     if (before)
  907.         wp->w_vsep_width = 1;
  908.     else
  909.     {
  910.         wp->w_vsep_width = oldwin->w_vsep_width;
  911.         oldwin->w_vsep_width = 1;
  912.     }
  913.     if (flags & (WSP_TOP | WSP_BOT))
  914.     {
  915.         if (flags & WSP_BOT)
  916.         frame_add_vsep(curfrp);
  917.         /* Set width of neighbor frame */
  918.         frame_new_width(curfrp, curfrp->fr_width
  919.             - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP);
  920.     }
  921.     else
  922.         oldwin->w_width -= new_size + 1;
  923.     if (before)    /* new window left of current one */
  924.     {
  925.         wp->w_wincol = oldwin->w_wincol;
  926.         oldwin->w_wincol += new_size + 1;
  927.     }
  928.     else        /* new window right of current one */
  929.         wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
  930.     frame_fix_width(oldwin);
  931.     frame_fix_width(wp);
  932.     }
  933.     else
  934. #endif
  935.     {
  936.     /* width and column of new window is same as current window */
  937. #ifdef FEAT_VERTSPLIT
  938.     if (flags & (WSP_TOP | WSP_BOT))
  939.     {
  940.         wp->w_wincol = 0;
  941.         wp->w_width = Columns;
  942.         wp->w_vsep_width = 0;
  943.     }
  944.     else
  945.     {
  946.         wp->w_wincol = oldwin->w_wincol;
  947.         wp->w_width = oldwin->w_width;
  948.         wp->w_vsep_width = oldwin->w_vsep_width;
  949.     }
  950.     frp->fr_width = curfrp->fr_width;
  951. #endif
  952.  
  953.     /* "new_size" of the current window goes to the new window, use
  954.      * one row for the status line */
  955.     win_new_height(wp, new_size);
  956.     if (flags & (WSP_TOP | WSP_BOT))
  957.         frame_new_height(curfrp, curfrp->fr_height
  958.                    - (new_size + STATUS_HEIGHT), flags & WSP_TOP);
  959.     else
  960.         win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
  961.     if (before)    /* new window above current one */
  962.     {
  963.         wp->w_winrow = oldwin->w_winrow;
  964.         wp->w_status_height = STATUS_HEIGHT;
  965.         oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
  966.     }
  967.     else        /* new window below current one */
  968.     {
  969.         wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
  970.         wp->w_status_height = oldwin->w_status_height;
  971.         oldwin->w_status_height = STATUS_HEIGHT;
  972.     }
  973. #ifdef FEAT_VERTSPLIT
  974.     if (flags & WSP_BOT)
  975.         frame_add_statusline(curfrp);
  976. #endif
  977.     frame_fix_height(wp);
  978.     frame_fix_height(oldwin);
  979.     }
  980.  
  981.     if (flags & (WSP_TOP | WSP_BOT))
  982.     (void)win_comp_pos();
  983.  
  984.     /*
  985.      * Both windows need redrawing
  986.      */
  987.     redraw_win_later(wp, NOT_VALID);
  988.     wp->w_redr_status = TRUE;
  989.     redraw_win_later(oldwin, NOT_VALID);
  990.     oldwin->w_redr_status = TRUE;
  991.  
  992.     if (need_status)
  993.     {
  994.     msg_row = Rows - 1;
  995.     msg_col = sc_col;
  996.     msg_clr_eos();    /* Old command/ruler may still be there -- webb */
  997.     comp_col();
  998.     msg_row = Rows - 1;
  999.     msg_col = 0;    /* put position back at start of line */
  1000.     }
  1001.  
  1002.     /*
  1003.      * make the new window the current window and redraw
  1004.      */
  1005.     if (do_equal || dir != 0)
  1006.     win_equal(wp,
  1007. #ifdef FEAT_VERTSPLIT
  1008.         (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
  1009.         : dir == 'h' ? 'b' :
  1010. #endif
  1011.         'v');
  1012.  
  1013.     /* Don't change the window height/width to 'winheight' / 'winwidth' if a
  1014.      * size was given. */
  1015. #ifdef FEAT_VERTSPLIT
  1016.     if (flags & WSP_VERT)
  1017.     {
  1018.     i = p_wiw;
  1019.     if (size != 0)
  1020.         p_wiw = size;
  1021.  
  1022. # ifdef FEAT_GUI
  1023.     /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
  1024.     if (gui.in_use)
  1025.         gui_init_which_components(NULL);
  1026. # endif
  1027.     }
  1028.     else
  1029. #endif
  1030.     {
  1031.     i = p_wh;
  1032.     if (size != 0)
  1033.         p_wh = size;
  1034.     }
  1035.     win_enter(wp, FALSE);
  1036. #ifdef FEAT_VERTSPLIT
  1037.     if (flags & WSP_VERT)
  1038.     p_wiw = i;
  1039.     else
  1040. #endif
  1041.     p_wh = i;
  1042.  
  1043.     return OK;
  1044. }
  1045.  
  1046. #endif /* FEAT_WINDOWS */
  1047.  
  1048. #ifdef FEAT_VERTSPLIT
  1049. /*
  1050.  * Return minimal height for window "wp" and windows east of it.
  1051.  * Takes into account the eastbound windws can be split, each of them
  1052.  * requireing p_wmh lines.  Doesn't count status lines.
  1053.  */
  1054.     static int
  1055. win_minheight(wp)
  1056.     win_T    *wp;
  1057. {
  1058.     int        minheight = p_wmh;
  1059.     int        n;
  1060.     win_T    *wp1, *wp2;
  1061.  
  1062.     wp1 = wp;
  1063.     for (;;)
  1064.     {
  1065.     wp1 = wp1->w_next;
  1066.     if (wp1 == NULL)
  1067.         break;
  1068.     n = p_wmh;
  1069.     wp2 = wp1;
  1070.     for (;;)
  1071.     {
  1072.         wp2 = wp2->w_next;
  1073.         if (wp2 == NULL)
  1074.         break;
  1075.         n += win_minheight(wp2);
  1076.     }
  1077.     if (n > minheight)
  1078.         minheight = n;
  1079.     }
  1080.     return minheight;
  1081. }
  1082.  
  1083. #endif
  1084.  
  1085. #if defined(FEAT_WINDOWS) || defined(PROTO)
  1086. /*
  1087.  * Check if "win" is a pointer to an existing window.
  1088.  */
  1089.     int
  1090. win_valid(win)
  1091.     win_T    *win;
  1092. {
  1093.     win_T    *wp;
  1094.  
  1095.     if (win == NULL)
  1096.     return FALSE;
  1097.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  1098.     if (wp == win)
  1099.         return TRUE;
  1100.     return FALSE;
  1101. }
  1102.  
  1103. /*
  1104.  * Return the number of windows.
  1105.  */
  1106.     int
  1107. win_count()
  1108. {
  1109.     win_T    *wp;
  1110.     int        count = 0;
  1111.  
  1112.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  1113.     ++count;
  1114.     return count;
  1115. }
  1116.  
  1117. /*
  1118.  * Make "count" windows on the screen.
  1119.  * Return actual number of windows on the screen.
  1120.  * Must be called when there is just one window, filling the whole screen
  1121.  * (excluding the command line).
  1122.  */
  1123. /*ARGSUSED*/
  1124.     int
  1125. make_windows(count, vertical)
  1126.     int        count;
  1127.     int        vertical;    /* split windows vertically if TRUE */
  1128. {
  1129.     int        maxcount;
  1130.     int        todo;
  1131.  
  1132. #ifdef FEAT_VERTSPLIT
  1133.     if (vertical)
  1134.     {
  1135.     /* Each windows needs at least 'winminwidth' lines and a separator
  1136.      * column. */
  1137.     maxcount = (curwin->w_width + curwin->w_vsep_width
  1138.                          - (p_wiw - p_wmw)) / (p_wmw + 1);
  1139.     }
  1140.     else
  1141. #endif
  1142.     {
  1143.     /* Each window needs at least 'winminheight' lines and a status line. */
  1144.     maxcount = (curwin->w_height + curwin->w_status_height
  1145.                   - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
  1146.     }
  1147.  
  1148.     if (maxcount < 2)
  1149.     maxcount = 2;
  1150.     if (count > maxcount)
  1151.     count = maxcount;
  1152.  
  1153.     /*
  1154.      * add status line now, otherwise first window will be too big
  1155.      */
  1156.     if (count > 1)
  1157.     last_status(TRUE);
  1158.  
  1159. #ifdef FEAT_AUTOCMD
  1160.     /*
  1161.      * Don't execute autocommands while creating the windows.  Must do that
  1162.      * when putting the buffers in the windows.
  1163.      */
  1164.     ++autocmd_busy;
  1165. #endif
  1166.  
  1167.     /* todo is number of windows left to create */
  1168.     for (todo = count - 1; todo > 0; --todo)
  1169. #ifdef FEAT_VERTSPLIT
  1170.     if (vertical)
  1171.     {
  1172.         if (win_split(curwin->w_width - (curwin->w_width - todo)
  1173.             / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
  1174.         break;
  1175.     }
  1176.     else
  1177. #endif
  1178.     {
  1179.         if (win_split(curwin->w_height - (curwin->w_height - todo
  1180.                 * STATUS_HEIGHT) / (todo + 1)
  1181.             - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
  1182.         break;
  1183.     }
  1184.  
  1185. #ifdef FEAT_AUTOCMD
  1186.     --autocmd_busy;
  1187. #endif
  1188.  
  1189.     /* return actual number of windows */
  1190.     return (count - todo);
  1191. }
  1192.  
  1193. /*
  1194.  * Exchange current and next window
  1195.  */
  1196.     static void
  1197. win_exchange(Prenum)
  1198.     long    Prenum;
  1199. {
  1200.     frame_T    *frp;
  1201.     frame_T    *frp2;
  1202.     win_T    *wp;
  1203.     win_T    *wp2;
  1204.     int        temp;
  1205.  
  1206.     if (lastwin == firstwin)        /* just one window */
  1207.     {
  1208.     beep_flush();
  1209.     return;
  1210.     }
  1211.  
  1212. #ifdef FEAT_GUI
  1213.     need_mouse_correct = TRUE;
  1214. #endif
  1215.  
  1216.     /*
  1217.      * find window to exchange with
  1218.      */
  1219.     if (Prenum)
  1220.     {
  1221.     frp = curwin->w_frame->fr_parent->fr_child;
  1222.     while (frp != NULL && --Prenum > 0)
  1223.         frp = frp->fr_next;
  1224.     }
  1225.     else if (curwin->w_frame->fr_next != NULL)    /* Swap with next */
  1226.     frp = curwin->w_frame->fr_next;
  1227.     else    /* Swap last window in row/col with previous */
  1228.     frp = curwin->w_frame->fr_prev;
  1229.  
  1230.     /* We can only exchange a window with another window, not with a frame
  1231.      * containing windows. */
  1232.     if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
  1233.     return;
  1234.     wp = frp->fr_win;
  1235.  
  1236. /*
  1237.  * 1. remove curwin from the list. Remember after which window it was in wp2
  1238.  * 2. insert curwin before wp in the list
  1239.  * if wp != wp2
  1240.  *    3. remove wp from the list
  1241.  *    4. insert wp after wp2
  1242.  * 5. exchange the status line height and vsep width.
  1243.  */
  1244.     wp2 = curwin->w_prev;
  1245.     frp2 = curwin->w_frame->fr_prev;
  1246.     if (wp->w_prev != curwin)
  1247.     {
  1248.     win_remove(curwin);
  1249.     frame_remove(curwin->w_frame);
  1250.     win_append(wp->w_prev, curwin);
  1251.     frame_insert(frp, curwin->w_frame);
  1252.     }
  1253.     if (wp != wp2)
  1254.     {
  1255.     win_remove(wp);
  1256.     frame_remove(wp->w_frame);
  1257.     win_append(wp2, wp);
  1258.     if (frp2 == NULL)
  1259.         frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
  1260.     else
  1261.         frame_append(frp2, wp->w_frame);
  1262.     }
  1263.     temp = curwin->w_status_height;
  1264.     curwin->w_status_height = wp->w_status_height;
  1265.     wp->w_status_height = temp;
  1266. #ifdef FEAT_VERTSPLIT
  1267.     temp = curwin->w_vsep_width;
  1268.     curwin->w_vsep_width = wp->w_vsep_width;
  1269.     wp->w_vsep_width = temp;
  1270.  
  1271.     /* If the windows are not in the same frame, exchange the sizes to avoid
  1272.      * messing up the window layout.  Otherwise fix the frame sizes. */
  1273.     if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
  1274.     {
  1275.     temp = curwin->w_height;
  1276.     curwin->w_height = wp->w_height;
  1277.     wp->w_height = temp;
  1278.     temp = curwin->w_width;
  1279.     curwin->w_width = wp->w_width;
  1280.     wp->w_width = temp;
  1281.     }
  1282.     else
  1283.     {
  1284.     frame_fix_height(curwin);
  1285.     frame_fix_height(wp);
  1286.     frame_fix_width(curwin);
  1287.     frame_fix_width(wp);
  1288.     }
  1289. #endif
  1290.  
  1291.     (void)win_comp_pos();        /* recompute window positions */
  1292.  
  1293.     win_enter(wp, TRUE);
  1294.     redraw_later(CLEAR);
  1295. }
  1296.  
  1297. /*
  1298.  * rotate windows: if upwards TRUE the second window becomes the first one
  1299.  *           if upwards FALSE the first window becomes the second one
  1300.  */
  1301.     static void
  1302. win_rotate(upwards, count)
  1303.     int        upwards;
  1304.     int        count;
  1305. {
  1306.     win_T    *wp1;
  1307.     win_T    *wp2;
  1308.     frame_T    *frp;
  1309.     int        n;
  1310.  
  1311.     if (firstwin == lastwin)        /* nothing to do */
  1312.     {
  1313.     beep_flush();
  1314.     return;
  1315.     }
  1316.  
  1317. #ifdef FEAT_GUI
  1318.     need_mouse_correct = TRUE;
  1319. #endif
  1320.  
  1321. #ifdef FEAT_VERTSPLIT
  1322.     /* Check if all frames in this row/col have one window. */
  1323.     for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
  1324.                                frp = frp->fr_next)
  1325.     if (frp->fr_win == NULL)
  1326.     {
  1327.         EMSG(_("E443: Cannot rotate when another window is split"));
  1328.         return;
  1329.     }
  1330. #endif
  1331.  
  1332.     while (count--)
  1333.     {
  1334.     if (upwards)        /* first window becomes last window */
  1335.     {
  1336.         /* remove first window/frame from the list */
  1337.         frp = curwin->w_frame->fr_parent->fr_child;
  1338.         wp1 = frp->fr_win;
  1339.         win_remove(wp1);
  1340.         frame_remove(frp);
  1341.  
  1342.         /* find last frame and append removed window/frame after it */
  1343.         for ( ; frp->fr_next != NULL; frp = frp->fr_next)
  1344.         ;
  1345.         win_append(frp->fr_win, wp1);
  1346.         frame_append(frp, wp1->w_frame);
  1347.  
  1348.         wp2 = frp->fr_win;        /* previously last window */
  1349.     }
  1350.     else            /* last window becomes first window */
  1351.     {
  1352.         /* find last window/frame in the list and remove it */
  1353.         for (frp = curwin->w_frame; frp->fr_next != NULL;
  1354.                                frp = frp->fr_next)
  1355.         ;
  1356.         wp1 = frp->fr_win;
  1357.         wp2 = wp1->w_prev;            /* will become last window */
  1358.         win_remove(wp1);
  1359.         frame_remove(frp);
  1360.  
  1361.         /* append the removed window/frame before the first in the list */
  1362.         win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
  1363.         frame_insert(frp->fr_parent->fr_child, frp);
  1364.     }
  1365.  
  1366.     /* exchange status height and vsep width of old and new last window */
  1367.     n = wp2->w_status_height;
  1368.     wp2->w_status_height = wp1->w_status_height;
  1369.     wp1->w_status_height = n;
  1370.     frame_fix_height(wp1);
  1371.     frame_fix_height(wp2);
  1372. #ifdef FEAT_VERTSPLIT
  1373.     n = wp2->w_vsep_width;
  1374.     wp2->w_vsep_width = wp1->w_vsep_width;
  1375.     wp1->w_vsep_width = n;
  1376.     frame_fix_width(wp1);
  1377.     frame_fix_width(wp2);
  1378. #endif
  1379.  
  1380.         /* recompute w_winrow and w_wincol for all windows */
  1381.     (void)win_comp_pos();
  1382.     }
  1383.  
  1384.     redraw_later(CLEAR);
  1385. }
  1386.  
  1387. /*
  1388.  * Move the current window to the very top/bottom/left/right of the screen.
  1389.  */
  1390.     static void
  1391. win_totop(size, flags)
  1392.     int        size;
  1393.     int        flags;
  1394. {
  1395.     int        dir;
  1396.  
  1397.     if (lastwin == firstwin)
  1398.     {
  1399.     beep_flush();
  1400.     return;
  1401.     }
  1402.  
  1403.     /* Remove the window and frame from the tree of frames. */
  1404.     (void)winframe_remove(curwin, &dir);
  1405.     win_remove(curwin);
  1406.     (void)win_comp_pos();
  1407.  
  1408.     /* Split a window on the right side and put the window there. */
  1409.     (void)win_split_ins(size, flags, curwin, dir);
  1410.  
  1411. #if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
  1412.     /* When 'guioptions' includes 'L' or 'R' may have to remove or add
  1413.      * scrollbars. */
  1414.     if (gui.in_use)
  1415.     gui_init_which_components(NULL);
  1416. #endif
  1417.  
  1418. }
  1419.  
  1420. /*
  1421.  * Move window "win1" to below/right of "win2" and make "win1" the current
  1422.  * window.  Only works within the same frame!
  1423.  */
  1424.     void
  1425. win_move_after(win1, win2)
  1426.     win_T    *win1, *win2;
  1427. {
  1428.     int        height;
  1429.  
  1430.     /* check if the arguments are reasonable */
  1431.     if (win1 == win2)
  1432.     return;
  1433.  
  1434.     /* check if there is something to do */
  1435.     if (win2->w_next != win1)
  1436.     {
  1437.     /* may need move the status line/vertical separator of the last window
  1438.      * */
  1439.     if (win1 == lastwin)
  1440.     {
  1441.         height = win1->w_prev->w_status_height;
  1442.         win1->w_prev->w_status_height = win1->w_status_height;
  1443.         win1->w_status_height = height;
  1444. #ifdef FEAT_VERTSPLIT
  1445.         win1->w_prev->w_vsep_width = 0;
  1446.         win1->w_vsep_width = 1;
  1447. #endif
  1448.     }
  1449.     else if (win2 == lastwin)
  1450.     {
  1451.         height = win1->w_status_height;
  1452.         win1->w_status_height = win2->w_status_height;
  1453.         win2->w_status_height = height;
  1454. #ifdef FEAT_VERTSPLIT
  1455.         win2->w_vsep_width = 1;
  1456.         win1->w_vsep_width = 0;
  1457. #endif
  1458.     }
  1459.     win_remove(win1);
  1460.     frame_remove(win1->w_frame);
  1461.     win_append(win2, win1);
  1462.     frame_append(win2->w_frame, win1->w_frame);
  1463.  
  1464.     (void)win_comp_pos();    /* recompute w_winrow for all windows */
  1465.     redraw_later(NOT_VALID);
  1466.     }
  1467.     win_enter(win1, FALSE);
  1468. }
  1469.  
  1470. /*
  1471.  * Make all windows the same height.
  1472.  * 'next_curwin' will soon be the current window, make sure it has enough
  1473.  * rows.
  1474.  */
  1475.     void
  1476. win_equal(next_curwin, dir)
  1477.     win_T    *next_curwin;    /* pointer to current window to be or NULL */
  1478.     int        dir;        /* 'v' for vertically, 'h' for horizontally,
  1479.                    'b' for both, 0 for using p_ead */
  1480. {
  1481.     if (dir == 0)
  1482. #ifdef FEAT_VERTSPLIT
  1483.     dir = *p_ead;
  1484. #else
  1485.     dir = 'b';
  1486. #endif
  1487.     win_equal_rec(next_curwin == NULL ? curwin : next_curwin, topframe, dir,
  1488.                      0, 0, (int)Columns, topframe->fr_height);
  1489. }
  1490.  
  1491. /*
  1492.  * Set a frame to a new position and height, spreading the available room
  1493.  * equally over contained frames.
  1494.  * The window "next_curwin" (if not NULL) should at least get the size from
  1495.  * 'winheight' and 'winwidth' if possible.
  1496.  */
  1497.     static void
  1498. win_equal_rec(next_curwin, topfr, dir, col, row, width, height)
  1499.     win_T    *next_curwin;    /* pointer to current window to be or NULL */
  1500.     frame_T    *topfr;        /* frame to set size off */
  1501.     int        dir;        /* 'v', 'h' or 'b', see win_equal() */
  1502.     int        col;        /* horizontal position for frame */
  1503.     int        row;        /* vertical position for frame */
  1504.     int        width;        /* new width of frame */
  1505.     int        height;        /* new height of frame */
  1506. {
  1507.     int        n, m;
  1508.     int        extra_sep = 0;
  1509.     int        wincount, totwincount = 0;
  1510.     frame_T    *fr;
  1511.     int        next_curwin_size = 0;
  1512.     int        room = 0;
  1513.     int        new_size;
  1514. #ifdef FEAT_QUICKFIX
  1515.     int        quickfix_height = 0;
  1516.     int        preview_height = 0;
  1517. #endif
  1518.     int        has_next_curwin = 0;
  1519.     int        hnc;
  1520.  
  1521.     if (topfr->fr_layout == FR_LEAF)
  1522.     {
  1523.     /* Set the width/height of this frame.
  1524.      * Redraw when size or position changes */
  1525.     if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
  1526. #ifdef FEAT_VERTSPLIT
  1527.         || topfr->fr_width != width || topfr->fr_win->w_wincol != col
  1528. #endif
  1529.        )
  1530.     {
  1531.         topfr->fr_win->w_winrow = row;
  1532.         frame_new_height(topfr, height, FALSE);
  1533. #ifdef FEAT_VERTSPLIT
  1534.         topfr->fr_win->w_wincol = col;
  1535.         frame_new_width(topfr, width, FALSE);
  1536. #endif
  1537.         redraw_all_later(CLEAR);
  1538.     }
  1539.     }
  1540. #ifdef FEAT_VERTSPLIT
  1541.     else if (topfr->fr_layout == FR_ROW)
  1542.     {
  1543.     topfr->fr_width = width;
  1544.     topfr->fr_height = height;
  1545.  
  1546.     if (dir != 'v')            /* equalize frame widths */
  1547.     {
  1548.         /* Compute the maximum number of windows horizontally in this
  1549.          * frame. */
  1550.         n = frame_minwidth(topfr, NOWIN);
  1551.         /* add one for the rightmost window, it doesn't have a separator */
  1552.         if (col + width == Columns)
  1553.         extra_sep = 1;
  1554.         else
  1555.         extra_sep = 0;
  1556.         totwincount = (n + extra_sep) / (p_wmw + 1);
  1557.  
  1558.         /* Compute room available for windows other than "next_curwin" */
  1559.         m = frame_minwidth(topfr, next_curwin);
  1560.         room = width - m;
  1561.         if (room < 0)
  1562.         {
  1563.         next_curwin_size = p_wiw + room;
  1564.         room = 0;
  1565.         }
  1566.         else if (n == m)        /* doesn't contain curwin */
  1567.         next_curwin_size = 0;
  1568.         else
  1569.         {
  1570.         next_curwin_size = (room + p_wiw + (totwincount - 1) * p_wmw
  1571.                        + (totwincount - 1)) / totwincount;
  1572.         if (next_curwin_size  > p_wiw)
  1573.             room -= next_curwin_size - p_wiw;
  1574.         else
  1575.             next_curwin_size = p_wiw;
  1576.         }
  1577.         if (n != m)
  1578.         --totwincount;        /* don't count curwin */
  1579.     }
  1580.  
  1581.     for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
  1582.     {
  1583.         n = m = 0;
  1584.         wincount = 1;
  1585.         if (fr->fr_next == NULL)
  1586.         /* last frame gets all that remains (avoid roundoff error) */
  1587.         new_size = width;
  1588.         else if (dir == 'v')
  1589.         new_size = fr->fr_width;
  1590.         else
  1591.         {
  1592.         /* Compute the maximum number of windows horiz. in "fr". */
  1593.         n = frame_minwidth(fr, NOWIN);
  1594.         wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
  1595.                                 / (p_wmw + 1);
  1596.         m = frame_minwidth(fr, next_curwin);
  1597.         if (n != m)        /* don't count next_curwin */
  1598.             --wincount;
  1599.         new_size = (wincount * room + ((unsigned)totwincount >> 1))
  1600.                                 / totwincount;
  1601.         if (n != m)        /* add next_curwin size */
  1602.         {
  1603.             next_curwin_size -= p_wiw - (m - n);
  1604.             new_size += next_curwin_size;
  1605.         }
  1606.         }
  1607.         win_equal_rec(next_curwin, fr, dir, col, row, new_size + n, height);
  1608.         col += new_size + n;
  1609.         width -= new_size + n;
  1610.         if (n != m)        /* contains curwin */
  1611.         room -= new_size - next_curwin_size;
  1612.         else
  1613.         room -= new_size;
  1614.         totwincount -= wincount;
  1615.     }
  1616.     }
  1617. #endif
  1618.     else /* topfr->fr_layout == FR_COL */
  1619.     {
  1620. #ifdef FEAT_VERTSPLIT
  1621.     topfr->fr_width = width;
  1622. #endif
  1623.     topfr->fr_height = height;
  1624.  
  1625.     if (dir != 'h')            /* equalize frame heights */
  1626.     {
  1627.         /* Compute maximum number of windows vertically in this frame. */
  1628.         n = frame_minheight(topfr, NOWIN);
  1629.         /* add one for the bottom window if it doesn't have a statusline */
  1630.         if (row + height == cmdline_row && p_ls == 0)
  1631.         extra_sep = 1;
  1632.         else
  1633.         extra_sep = 0;
  1634.         totwincount = (n + extra_sep) / (p_wmh + 1);
  1635.         has_next_curwin = frame_has_win(topfr, next_curwin);
  1636.  
  1637.         /*
  1638.          * Compute height for "next_curwin" window and room available for
  1639.          * other windows.
  1640.          * "m" is the minimal height when counting p_wh for "next_curwin".
  1641.          */
  1642.         m = frame_minheight(topfr, next_curwin);
  1643.         room = height - m;
  1644.         if (room < 0)
  1645.         {
  1646.         /* The room is less then 'winheight', use all space for the
  1647.          * current window. */
  1648.         next_curwin_size = p_wh + room;
  1649.         room = 0;
  1650.         }
  1651.         else
  1652.         {
  1653. #ifdef FEAT_QUICKFIX
  1654.         next_curwin_size = -1;
  1655.         for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
  1656.         {
  1657.             /* The quickfix and preview window keep their height if
  1658.              * possible.
  1659.              * Watch out for this window being the next_curwin. */
  1660.             if (fr->fr_win != NULL
  1661.                 && (bt_quickfix(fr->fr_win->w_buffer)
  1662.                 || fr->fr_win->w_p_pvw))
  1663.             {
  1664.             new_size = fr->fr_height;
  1665.             if (fr->fr_win == next_curwin)
  1666.             {
  1667.                 room += p_wh - p_wmh;
  1668.                 next_curwin_size = 0;
  1669.                 if (new_size < p_wh)
  1670.                 new_size = p_wh;
  1671.             }
  1672.             else
  1673.                 --totwincount;
  1674.             room -= new_size - p_wmh - fr->fr_win->w_status_height;
  1675.             if (room < 0)
  1676.             {
  1677.                 new_size += room;
  1678.                 room = 0;
  1679.             }
  1680.             if (fr->fr_win->w_p_pvw)
  1681.                 preview_height = new_size;
  1682.             else
  1683.                 quickfix_height = new_size;
  1684.             }
  1685.         }
  1686.         if (next_curwin_size == -1)
  1687. #endif
  1688.         {
  1689.             if (!has_next_curwin)
  1690.             next_curwin_size = 0;
  1691.             else if (totwincount > 1
  1692.                 && (room + (totwincount - 2))
  1693.                            / (totwincount - 1) > p_wh)
  1694.             {
  1695.             next_curwin_size = (room + p_wh + totwincount * p_wmh
  1696.                        + (totwincount - 1)) / totwincount;
  1697.             room -= next_curwin_size - p_wh;
  1698.             }
  1699.             else
  1700.             next_curwin_size = p_wh;
  1701.         }
  1702.         }
  1703.  
  1704.         if (has_next_curwin)
  1705.         --totwincount;        /* don't count curwin */
  1706.     }
  1707.  
  1708.     for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
  1709.     {
  1710.         n = m = 0;
  1711.         wincount = 1;
  1712.         if (fr->fr_next == NULL)
  1713.         /* last frame gets all that remains (avoid roundoff error) */
  1714.         new_size = height;
  1715.         else if (dir == 'h')
  1716.         new_size = fr->fr_height;
  1717. #ifdef FEAT_QUICKFIX
  1718.         else if (fr->fr_win != NULL && bt_quickfix(fr->fr_win->w_buffer))
  1719.         {
  1720.         new_size = quickfix_height;
  1721.         wincount = 0;        /* doesn't count as a sizeable window */
  1722.         }
  1723.         else if (fr->fr_win != NULL && fr->fr_win->w_p_pvw)
  1724.         {
  1725.         new_size = preview_height;
  1726.         wincount = 0;        /* doesn't count as a sizeable window */
  1727.         }
  1728. #endif
  1729.         else
  1730.         {
  1731.         /* Compute the maximum number of windows vert. in "fr". */
  1732.         n = frame_minheight(fr, NOWIN);
  1733.         wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
  1734.                                 / (p_wmh + 1);
  1735.         m = frame_minheight(fr, next_curwin);
  1736.         if (has_next_curwin)
  1737.             hnc = frame_has_win(fr, next_curwin);
  1738.         else
  1739.             hnc = FALSE;
  1740.         if (hnc)        /* don't count next_curwin */
  1741.             --wincount;
  1742.         if (totwincount == 0)
  1743.             new_size = room;
  1744.         else
  1745.             new_size = (wincount * room + ((unsigned)totwincount >> 1))
  1746.                                 / totwincount;
  1747.         if (hnc)        /* add next_curwin size */
  1748.         {
  1749.             next_curwin_size -= p_wh - (m - n);
  1750.             new_size += next_curwin_size;
  1751.             room -= new_size - next_curwin_size;
  1752.         }
  1753.         else
  1754.             room -= new_size;
  1755.         new_size += n;
  1756.         }
  1757.         win_equal_rec(next_curwin, fr, dir, col, row, width, new_size);
  1758.         row += new_size;
  1759.         height -= new_size;
  1760.         totwincount -= wincount;
  1761.     }
  1762.     }
  1763. }
  1764.  
  1765. /*
  1766.  * close all windows for buffer 'buf'
  1767.  */
  1768.     void
  1769. close_windows(buf)
  1770.     buf_T    *buf;
  1771. {
  1772.     win_T    *win;
  1773.  
  1774.     ++RedrawingDisabled;
  1775.     for (win = firstwin; win != NULL && lastwin != firstwin; )
  1776.     {
  1777.     if (win->w_buffer == buf)
  1778.     {
  1779.         win_close(win, FALSE);
  1780.         win = firstwin;        /* go back to the start */
  1781.     }
  1782.     else
  1783.         win = win->w_next;
  1784.     }
  1785.     --RedrawingDisabled;
  1786. }
  1787.  
  1788. /*
  1789.  * close window "win"
  1790.  * If "free_buf" is TRUE related buffer may be unloaded.
  1791.  *
  1792.  * called by :quit, :close, :xit, :wq and findtag()
  1793.  */
  1794.     void
  1795. win_close(win, free_buf)
  1796.     win_T    *win;
  1797.     int        free_buf;
  1798. {
  1799.     win_T    *wp;
  1800. #ifdef FEAT_AUTOCMD
  1801.     int        other_buffer = FALSE;
  1802. #endif
  1803.     int        close_curwin = FALSE;
  1804.     frame_T    *frp;
  1805.     int        dir;
  1806.     int        help_window = FALSE;
  1807.  
  1808.     if (lastwin == firstwin)
  1809.     {
  1810.     EMSG(_("E444: Cannot close last window"));
  1811.     return;
  1812.     }
  1813.  
  1814.     /* When closing the help window, try restoring a snapshot after closing
  1815.      * the window.  Otherwise clear the snapshot, it's now invalid. */
  1816.     if (win->w_buffer->b_help)
  1817.     help_window = TRUE;
  1818.     else
  1819.     clear_snapshot();
  1820.  
  1821. #ifdef FEAT_AUTOCMD
  1822.     if (win == curwin)
  1823.     {
  1824.     /*
  1825.      * Guess which window is going to be the new current window.
  1826.      * This may change because of the autocommands (sigh).
  1827.      */
  1828.     wp = frame2win(win_altframe(win));
  1829.  
  1830.     /*
  1831.      * Be careful: If autocommands delete the window, return now.
  1832.      */
  1833.     if (wp->w_buffer != curbuf)
  1834.     {
  1835.         other_buffer = TRUE;
  1836.         apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
  1837.         if (!win_valid(win) || firstwin == lastwin)
  1838.         return;
  1839.     }
  1840.     apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
  1841.     if (!win_valid(win) || firstwin == lastwin)
  1842.         return;
  1843.     }
  1844. #endif
  1845.  
  1846.     /*
  1847.      * Close the link to the buffer.
  1848.      */
  1849.     close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
  1850.     /* Autocommands may have closed the window already, or closed the only
  1851.      * other window. */
  1852.     if (!win_valid(win) || firstwin == lastwin)
  1853.     return;
  1854.  
  1855.     /* reduce the reference count to the argument list. */
  1856.     alist_unlink(curwin->w_alist);
  1857.  
  1858.     /* remove the window and its frame from the tree of frames. */
  1859.     frp = win->w_frame;
  1860.     wp = winframe_remove(win, &dir);
  1861.     vim_free(frp);
  1862.     win_free(win);
  1863.  
  1864.     /* Make sure curwin isn't invalid.  It can cause severe trouble when
  1865.      * printing an error message.  For win_equal() curbuf needs to be valid
  1866.      * too. */
  1867.     if (win == curwin)
  1868.     {
  1869.     curwin = wp;
  1870. #ifdef FEAT_QUICKFIX
  1871.     if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
  1872.     {
  1873.         /*
  1874.          * When the cursor goes to the preview or the quickfix window, try
  1875.          * finding another window to go to.
  1876.          */
  1877.         for (;;)
  1878.         {
  1879.         if (wp->w_next == NULL)
  1880.             wp = firstwin;
  1881.         else
  1882.             wp = wp->w_next;
  1883.         if (wp == curwin)
  1884.             break;
  1885.         if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
  1886.         {
  1887.             curwin = wp;
  1888.             break;
  1889.         }
  1890.         }
  1891.     }
  1892. #endif
  1893.     curbuf = curwin->w_buffer;
  1894.     close_curwin = TRUE;
  1895.     }
  1896.     if (p_ea)
  1897.     win_equal(curwin,
  1898. #ifdef FEAT_VERTSPLIT
  1899.         dir
  1900. #else
  1901.         0
  1902. #endif
  1903.         );
  1904.     else
  1905.     win_comp_pos();
  1906.     if (close_curwin)
  1907.     {
  1908.     win_enter_ext(wp, FALSE, TRUE);
  1909. #ifdef FEAT_AUTOCMD
  1910.     if (other_buffer)
  1911.         /* careful: after this wp and win may be invalid! */
  1912.         apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  1913. #endif
  1914.     }
  1915.  
  1916.     /*
  1917.      * if last window has a status line now and we don't want one,
  1918.      * remove the status line
  1919.      */
  1920.     last_status(FALSE);
  1921.  
  1922.     /* After closing the help window, try restoring the window layout from
  1923.      * before it was opened. */
  1924.     if (help_window)
  1925.     restore_snapshot(close_curwin);
  1926.  
  1927. #if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
  1928.     /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
  1929.     if (gui.in_use && !win_hasvertsplit())
  1930.     gui_init_which_components(NULL);
  1931. #endif
  1932.  
  1933.     redraw_all_later(NOT_VALID);
  1934. }
  1935.  
  1936. /*
  1937.  * Remove a window and its frame from the tree of frames.
  1938.  * Returns a pointer to the window that got the freed up space.
  1939.  */
  1940. /*ARGSUSED*/
  1941.     static win_T *
  1942. winframe_remove(win, dirp)
  1943.     win_T    *win;
  1944.     int        *dirp;        /* set to 'v' or 'h' for direction if 'ea' */
  1945. {
  1946.     frame_T    *frp, *frp2, *frp3;
  1947.     frame_T    *frp_close = win->w_frame;
  1948.     win_T    *wp;
  1949.  
  1950.     /*
  1951.      * Remove the window from its frame.
  1952.      */
  1953.     frp2 = win_altframe(win);
  1954.     wp = frame2win(frp2);
  1955.  
  1956.     /* Remove this frame from the list of frames. */
  1957.     frame_remove(frp_close);
  1958.  
  1959.     /* If rows/columns go to a window below/right its positions need to be
  1960.      * updated. */
  1961.     if (frp2 == frp_close->fr_next)
  1962.     {
  1963.     int row = win->w_winrow;
  1964.     int col = W_WINCOL(win);
  1965.  
  1966.     frame_comp_pos(frp2, &row, &col);
  1967.     }
  1968.  
  1969. #ifdef FEAT_VERTSPLIT
  1970.     if (frp_close->fr_parent->fr_layout == FR_COL)
  1971.     {
  1972. #endif
  1973. #ifdef FEAT_QUICKFIX
  1974.     int    old_height = 0;
  1975.  
  1976.     /* For a preview or quickfix window, remember its old size and restore
  1977.      * it later (it's a simplistic solution...).  Don't do this if the
  1978.      * window will occupy the full height of the screen. */
  1979.     if (frp2->fr_win != NULL
  1980.         && (frp2->fr_next != NULL
  1981.             || frp2->fr_prev != NULL)
  1982.         && (frp2->fr_win->w_p_pvw
  1983.             || bt_quickfix(frp2->fr_win->w_buffer)))
  1984.         old_height = frp2->fr_win->w_height;
  1985. #endif
  1986.     frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
  1987.                    frp2 == frp_close->fr_next ? TRUE : FALSE);
  1988. #ifdef FEAT_QUICKFIX
  1989.     if (old_height != 0)
  1990.         win_setheight_win(old_height, frp2->fr_win);
  1991. #endif
  1992. #ifdef FEAT_VERTSPLIT
  1993.     *dirp = 'v';
  1994.     }
  1995.     else
  1996.     {
  1997.     frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
  1998.                    frp2 == frp_close->fr_next ? TRUE : FALSE);
  1999.     *dirp = 'h';
  2000.     }
  2001. #endif
  2002.  
  2003.     if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
  2004.     {
  2005.     /* There is no other frame in this list, move its info to the parent
  2006.      * and remove it. */
  2007.     frp2->fr_parent->fr_layout = frp2->fr_layout;
  2008.     frp2->fr_parent->fr_child = frp2->fr_child;
  2009.     for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
  2010.         frp->fr_parent = frp2->fr_parent;
  2011.     frp2->fr_parent->fr_win = frp2->fr_win;
  2012.     if (frp2->fr_win != NULL)
  2013.         frp2->fr_win->w_frame = frp2->fr_parent;
  2014.     frp = frp2->fr_parent;
  2015.     vim_free(frp2);
  2016.  
  2017.     frp2 = frp->fr_parent;
  2018.     if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
  2019.     {
  2020.         /* The frame above the parent has the same layout, have to merge
  2021.          * the frames into this list. */
  2022.         if (frp2->fr_child == frp)
  2023.         frp2->fr_child = frp->fr_child;
  2024.         frp->fr_child->fr_prev = frp->fr_prev;
  2025.         if (frp->fr_prev != NULL)
  2026.         frp->fr_prev->fr_next = frp->fr_child;
  2027.         for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
  2028.         {
  2029.         frp3->fr_parent = frp2;
  2030.         if (frp3->fr_next == NULL)
  2031.         {
  2032.             frp3->fr_next = frp->fr_next;
  2033.             if (frp->fr_next != NULL)
  2034.             frp->fr_next->fr_prev = frp3;
  2035.             break;
  2036.         }
  2037.         }
  2038.         vim_free(frp);
  2039.     }
  2040.     }
  2041.  
  2042.     return wp;
  2043. }
  2044.  
  2045. /*
  2046.  * Find out which frame is going to get the freed up space when "win" is
  2047.  * closed.
  2048.  * if 'splitbelow'/'splitleft' the space goes to the window above/left.
  2049.  * if 'nosplitbelow'/'nosplitleft' the space goes to the window below/right.
  2050.  * This makes opening a window and closing it immediately keep the same window
  2051.  * layout.
  2052.  */
  2053.     static frame_T *
  2054. win_altframe(win)
  2055.     win_T    *win;
  2056. {
  2057.     frame_T    *frp;
  2058.     int        b;
  2059.  
  2060.     frp = win->w_frame;
  2061. #ifdef FEAT_VERTSPLIT
  2062.     if (frp->fr_parent->fr_layout == FR_ROW)
  2063.     b = p_spr;
  2064.     else
  2065. #endif
  2066.     b = p_sb;
  2067.     if ((!b && frp->fr_next != NULL) || frp->fr_prev == NULL)
  2068.     return frp->fr_next;
  2069.     return frp->fr_prev;
  2070. }
  2071.  
  2072. /*
  2073.  * Find the left-upper window in frame "frp".
  2074.  */
  2075.     static win_T *
  2076. frame2win(frp)
  2077.     frame_T    *frp;
  2078. {
  2079.     while (frp->fr_win == NULL)
  2080.     frp = frp->fr_child;
  2081.     return frp->fr_win;
  2082. }
  2083.  
  2084. /*
  2085.  * Return TRUE if frame "frp" contains window "wp".
  2086.  */
  2087.     static int
  2088. frame_has_win(frp, wp)
  2089.     frame_T    *frp;
  2090.     win_T    *wp;
  2091. {
  2092.     frame_T    *p;
  2093.  
  2094.     if (frp->fr_layout == FR_LEAF)
  2095.     return frp->fr_win == wp;
  2096.  
  2097.     for (p = frp->fr_child; p != NULL; p = p->fr_next)
  2098.     if (frame_has_win(p, wp))
  2099.         return TRUE;
  2100.     return FALSE;
  2101. }
  2102.  
  2103. /*
  2104.  * Set a new height for a frame.  Recursively sets the height for contained
  2105.  * frames and windows.  Caller must take care of positions.
  2106.  */
  2107.     static void
  2108. frame_new_height(topfrp, height, topfirst)
  2109.     frame_T    *topfrp;
  2110.     int        height;
  2111.     int        topfirst;    /* resize topmost contained frame first */
  2112. {
  2113.     frame_T    *frp;
  2114.     int        extra_lines;
  2115.     int        h;
  2116.  
  2117.     if (topfrp->fr_win != NULL)
  2118.     {
  2119.     /* Simple case: just one window. */
  2120.     win_new_height(topfrp->fr_win,
  2121.                     height - topfrp->fr_win->w_status_height);
  2122.     }
  2123. #ifdef FEAT_VERTSPLIT
  2124.     else if (topfrp->fr_layout == FR_ROW)
  2125.     {
  2126.     /* All frames in this row get the same new height. */
  2127.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2128.         frame_new_height(frp, height, topfirst);
  2129.     }
  2130. #endif
  2131.     else
  2132.     {
  2133.     /* Complicated case: Resize a column of frames.  Resize the bottom
  2134.      * frame first, frames above that when needed. */
  2135.  
  2136.     frp = topfrp->fr_child;
  2137.     if (!topfirst)
  2138.         /* Find the bottom frame of this column */
  2139.         while (frp->fr_next != NULL)
  2140.         frp = frp->fr_next;
  2141.  
  2142.     extra_lines = height - topfrp->fr_height;
  2143.     if (extra_lines < 0)
  2144.     {
  2145.         /* reduce frame height, bottom frame first */
  2146.         while (frp != NULL)
  2147.         {
  2148.         h = frame_minheight(frp, NULL);
  2149.         if (frp->fr_height + extra_lines < h)
  2150.         {
  2151.             extra_lines += frp->fr_height - h;
  2152.             frame_new_height(frp, h, topfirst);
  2153.         }
  2154.         else
  2155.         {
  2156.             frame_new_height(frp, frp->fr_height + extra_lines,
  2157.                                     topfirst);
  2158.             break;
  2159.         }
  2160.         if (topfirst)
  2161.             frp = frp->fr_next;
  2162.         else
  2163.             frp = frp->fr_prev;
  2164.         }
  2165.     }
  2166.     else if (extra_lines > 0)
  2167.     {
  2168.         /* increase height of bottom or top frame */
  2169.         frame_new_height(frp, frp->fr_height + extra_lines, topfirst);
  2170.     }
  2171.     }
  2172.     topfrp->fr_height = height;
  2173. }
  2174.  
  2175. #ifdef FEAT_VERTSPLIT
  2176. /*
  2177.  * Add a status line to windows at the bottom of "frp".
  2178.  * Note: Does not check if there is room!
  2179.  */
  2180.     static void
  2181. frame_add_statusline(frp)
  2182.     frame_T    *frp;
  2183. {
  2184.     win_T    *wp;
  2185.  
  2186.     if (frp->fr_layout == FR_LEAF)
  2187.     {
  2188.     wp = frp->fr_win;
  2189.     if (wp->w_status_height == 0)
  2190.     {
  2191.         if (wp->w_height > 0)    /* don't make it negative */
  2192.         --wp->w_height;
  2193.         wp->w_status_height = STATUS_HEIGHT;
  2194.     }
  2195.     }
  2196.     else if (frp->fr_layout == FR_ROW)
  2197.     {
  2198.     /* Handle all the frames in the row. */
  2199.     for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
  2200.         frame_add_statusline(frp);
  2201.     }
  2202.     else /* frp->fr_layout == FR_COL */
  2203.     {
  2204.     /* Only need to handle the last frame in the column. */
  2205.     for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
  2206.         ;
  2207.     frame_add_statusline(frp);
  2208.     }
  2209. }
  2210.  
  2211. /*
  2212.  * Set width of a frame.  Handles recursively going through contained frames.
  2213.  * May remove separator line for windows at the right side (for win_close()).
  2214.  */
  2215.     static void
  2216. frame_new_width(topfrp, width, leftfirst)
  2217.     frame_T    *topfrp;
  2218.     int        width;
  2219.     int        leftfirst;    /* resize leftmost contained frame first */
  2220. {
  2221.     frame_T    *frp;
  2222.     int        extra_cols;
  2223.     int        w;
  2224.     win_T    *wp;
  2225.  
  2226.     if (topfrp->fr_layout == FR_LEAF)
  2227.     {
  2228.     /* Simple case: just one window. */
  2229.     wp = topfrp->fr_win;
  2230.     /* Find out if there are any windows right of this one. */
  2231.     for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
  2232.         if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
  2233.         break;
  2234.     if (frp->fr_parent == NULL)
  2235.         wp->w_vsep_width = 0;
  2236.     win_new_width(wp, width - wp->w_vsep_width);
  2237.     }
  2238.     else if (topfrp->fr_layout == FR_COL)
  2239.     {
  2240.     /* All frames in this column get the same new width. */
  2241.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2242.         frame_new_width(frp, width, leftfirst);
  2243.     }
  2244.     else    /* fr_layout == FR_ROW */
  2245.     {
  2246.     /* Complicated case: Resize a row of frames.  Resize the rightmost
  2247.      * frame first, frames left of it when needed. */
  2248.  
  2249.     /* Find the rightmost frame of this row */
  2250.     frp = topfrp->fr_child;
  2251.     if (!leftfirst)
  2252.         while (frp->fr_next != NULL)
  2253.         frp = frp->fr_next;
  2254.  
  2255.     extra_cols = width - topfrp->fr_width;
  2256.     if (extra_cols < 0)
  2257.     {
  2258.         /* reduce frame width, rightmost frame first */
  2259.         while (frp != NULL)
  2260.         {
  2261.         w = frame_minwidth(frp, NULL);
  2262.         if (frp->fr_width + extra_cols < w)
  2263.         {
  2264.             extra_cols += frp->fr_width - w;
  2265.             frame_new_width(frp, w, leftfirst);
  2266.         }
  2267.         else
  2268.         {
  2269.             frame_new_width(frp, frp->fr_width + extra_cols, leftfirst);
  2270.             break;
  2271.         }
  2272.         if (leftfirst)
  2273.             frp = frp->fr_next;
  2274.         else
  2275.             frp = frp->fr_prev;
  2276.         }
  2277.     }
  2278.     else if (extra_cols > 0)
  2279.     {
  2280.         /* increase width of rightmost frame */
  2281.         frame_new_width(frp, frp->fr_width + extra_cols, leftfirst);
  2282.     }
  2283.     }
  2284.     topfrp->fr_width = width;
  2285. }
  2286.  
  2287. /*
  2288.  * Add the vertical separator to windows at the right side of "frp".
  2289.  * Note: Does not check if there is room!
  2290.  */
  2291.     static void
  2292. frame_add_vsep(frp)
  2293.     frame_T    *frp;
  2294. {
  2295.     win_T    *wp;
  2296.  
  2297.     if (frp->fr_layout == FR_LEAF)
  2298.     {
  2299.     wp = frp->fr_win;
  2300.     if (wp->w_vsep_width == 0)
  2301.     {
  2302.         if (wp->w_width > 0)    /* don't make it negative */
  2303.         --wp->w_width;
  2304.         wp->w_vsep_width = 1;
  2305.     }
  2306.     }
  2307.     else if (frp->fr_layout == FR_COL)
  2308.     {
  2309.     /* Handle all the frames in the column. */
  2310.     for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
  2311.         frame_add_vsep(frp);
  2312.     }
  2313.     else /* frp->fr_layout == FR_ROW */
  2314.     {
  2315.     /* Only need to handle the last frame in the row. */
  2316.     frp = frp->fr_child;
  2317.     while (frp->fr_next != NULL)
  2318.         frp = frp->fr_next;
  2319.     frame_add_vsep(frp);
  2320.     }
  2321. }
  2322.  
  2323. /*
  2324.  * Set frame width from the window it contains.
  2325.  */
  2326.     static void
  2327. frame_fix_width(wp)
  2328.     win_T    *wp;
  2329. {
  2330.     wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
  2331. }
  2332. #endif
  2333.  
  2334. /*
  2335.  * Set frame height from the window it contains.
  2336.  */
  2337.     static void
  2338. frame_fix_height(wp)
  2339.     win_T    *wp;
  2340. {
  2341.     wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
  2342. }
  2343.  
  2344. /*
  2345.  * Compute the minimal height for frame "topfrp".
  2346.  * Uses the 'winminheight' option.
  2347.  * When "next_curwin" isn't NULL, use p_wh for this window.
  2348.  * When "next_curwin" is NOWIN, don't use at least one line for the current
  2349.  * window.
  2350.  */
  2351.     static int
  2352. frame_minheight(topfrp, next_curwin)
  2353.     frame_T    *topfrp;
  2354.     win_T    *next_curwin;
  2355. {
  2356.     frame_T    *frp;
  2357.     int        m;
  2358. #ifdef FEAT_VERTSPLIT
  2359.     int        n;
  2360. #endif
  2361.  
  2362.     if (topfrp->fr_win != NULL)
  2363.     {
  2364.     if (topfrp->fr_win == next_curwin)
  2365.         m = p_wh + topfrp->fr_win->w_status_height;
  2366.     else
  2367.     {
  2368.         /* window: minimal height of the window plus status line */
  2369.         m = p_wmh + topfrp->fr_win->w_status_height;
  2370.         /* Current window is minimal one line high */
  2371.         if (p_wmh == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
  2372.         ++m;
  2373.     }
  2374.     }
  2375. #ifdef FEAT_VERTSPLIT
  2376.     else if (topfrp->fr_layout == FR_ROW)
  2377.     {
  2378.     /* get the minimal height from each frame in this row */
  2379.     m = 0;
  2380.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2381.     {
  2382.         n = frame_minheight(frp, next_curwin);
  2383.         if (n > m)
  2384.         m = n;
  2385.     }
  2386.     }
  2387. #endif
  2388.     else
  2389.     {
  2390.     /* Add up the minimal heights for all frames in this column. */
  2391.     m = 0;
  2392.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2393.         m += frame_minheight(frp, next_curwin);
  2394.     }
  2395.  
  2396.     return m;
  2397. }
  2398.  
  2399. #ifdef FEAT_VERTSPLIT
  2400. /*
  2401.  * Compute the minimal width for frame "topfrp".
  2402.  * When "next_curwin" isn't NULL, use p_wiw for this window.
  2403.  * When "next_curwin" is NOWIN, don't use at least one column for the current
  2404.  * window.
  2405.  */
  2406.     static int
  2407. frame_minwidth(topfrp, next_curwin)
  2408.     frame_T    *topfrp;
  2409.     win_T    *next_curwin;    /* use p_wh and p_wiw for next_curwin */
  2410. {
  2411.     frame_T    *frp;
  2412.     int        m, n;
  2413.  
  2414.     if (topfrp->fr_win != NULL)
  2415.     {
  2416.     if (topfrp->fr_win == next_curwin)
  2417.         m = p_wiw + topfrp->fr_win->w_vsep_width;
  2418.     else
  2419.     {
  2420.         /* window: minimal width of the window plus separator column */
  2421.         m = p_wmw + topfrp->fr_win->w_vsep_width;
  2422.         /* Current window is minimal one column wide */
  2423.         if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
  2424.         ++m;
  2425.     }
  2426.     }
  2427.     else if (topfrp->fr_layout == FR_COL)
  2428.     {
  2429.     /* get the minimal width from each frame in this column */
  2430.     m = 0;
  2431.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2432.     {
  2433.         n = frame_minwidth(frp, next_curwin);
  2434.         if (n > m)
  2435.         m = n;
  2436.     }
  2437.     }
  2438.     else
  2439.     {
  2440.     /* Add up the minimal widths for all frames in this row. */
  2441.     m = 0;
  2442.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  2443.         m += frame_minwidth(frp, next_curwin);
  2444.     }
  2445.  
  2446.     return m;
  2447. }
  2448. #endif
  2449.  
  2450.  
  2451. /*
  2452.  * Try to close all windows except current one.
  2453.  * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
  2454.  * used and the buffer was modified.
  2455.  *
  2456.  * Used by ":bdel" and ":only".
  2457.  */
  2458.     void
  2459. close_others(message, forceit)
  2460.     int        message;
  2461.     int        forceit;        /* always hide all other windows */
  2462. {
  2463.     win_T    *wp;
  2464.     win_T    *nextwp;
  2465.     int        r;
  2466.  
  2467.     if (lastwin == firstwin)
  2468.     {
  2469.     if (message
  2470. #ifdef FEAT_AUTOCMD
  2471.             && !autocmd_busy
  2472. #endif
  2473.                     )
  2474.         MSG(_("Already only one window"));
  2475.     return;
  2476.     }
  2477.  
  2478.     /* Be very careful here: autocommands may change the window layout. */
  2479.     for (wp = firstwin; win_valid(wp); wp = nextwp)
  2480.     {
  2481.     nextwp = wp->w_next;
  2482.     if (wp != curwin)        /* don't close current window */
  2483.     {
  2484.  
  2485.         /* Check if it's allowed to abandon this window */
  2486.         r = can_abandon(wp->w_buffer, forceit);
  2487. #ifdef FEAT_AUTOCMD
  2488.         if (!win_valid(wp))        /* autocommands messed wp up */
  2489.         {
  2490.         nextwp = firstwin;
  2491.         continue;
  2492.         }
  2493. #endif
  2494.         if (!r)
  2495.         {
  2496. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  2497.         if (message && (p_confirm || cmdmod.confirm))
  2498.         {
  2499.             dialog_changed(wp->w_buffer, FALSE);
  2500. #ifdef FEAT_AUTOCMD
  2501.             if (!win_valid(wp))        /* autocommands messed wp up */
  2502.             {
  2503.             nextwp = firstwin;
  2504.             continue;
  2505.             }
  2506. #endif
  2507.         }
  2508.         if (bufIsChanged(wp->w_buffer))
  2509. #endif
  2510.             continue;
  2511.         }
  2512.         win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
  2513.     }
  2514.     }
  2515.  
  2516.     /*
  2517.      * If current window has a status line and we don't want one,
  2518.      * remove the status line.
  2519.      */
  2520.     if (lastwin != firstwin)
  2521.     EMSG(_("E445: Other window contains changes"));
  2522. }
  2523.  
  2524. #endif /* FEAT_WINDOWS */
  2525.  
  2526. /*
  2527.  * init the cursor in the window
  2528.  *
  2529.  * called when a new file is being edited
  2530.  */
  2531.     void
  2532. win_init(wp)
  2533.     win_T    *wp;
  2534. {
  2535.     redraw_win_later(wp, NOT_VALID);
  2536.     wp->w_lines_valid = 0;
  2537.     wp->w_cursor.lnum = 1;
  2538.     wp->w_curswant = wp->w_cursor.col = 0;
  2539. #ifdef FEAT_VIRTUALEDIT
  2540.     wp->w_cursor.coladd = 0;
  2541. #endif
  2542.     wp->w_pcmark.lnum = 1;    /* pcmark not cleared but set to line 1 */
  2543.     wp->w_pcmark.col = 0;
  2544.     wp->w_prev_pcmark.lnum = 0;
  2545.     wp->w_prev_pcmark.col = 0;
  2546.     wp->w_topline = 1;
  2547. #ifdef FEAT_DIFF
  2548.     wp->w_topfill = 0;
  2549. #endif
  2550.     wp->w_botline = 2;
  2551. #ifdef FEAT_FKMAP
  2552.     if (curwin->w_p_rl)
  2553.     wp->w_farsi = W_CONV + W_R_L;
  2554.     else
  2555.     wp->w_farsi = W_CONV;
  2556. #endif
  2557. }
  2558.  
  2559. /*
  2560.  * Allocate the first window and put an empty buffer in it.
  2561.  * Called from main().
  2562.  * When this fails we can't do anything: exit.
  2563.  */
  2564.     void
  2565. win_alloc_first()
  2566. {
  2567.     curwin = win_alloc(NULL);
  2568.     curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
  2569.     if (curwin == NULL || curbuf == NULL)
  2570.     mch_exit(0);
  2571.     curwin->w_buffer = curbuf;
  2572.     curbuf->b_nwindows = 1;    /* there is one window */
  2573. #ifdef FEAT_WINDOWS
  2574.     curwin->w_alist = &global_alist;
  2575. #endif
  2576.     win_init(curwin);        /* init current window */
  2577.  
  2578.     topframe = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
  2579.     if (topframe == NULL)
  2580.     mch_exit(0);
  2581.     topframe->fr_layout = FR_LEAF;
  2582. #ifdef FEAT_VERTSPLIT
  2583.     topframe->fr_width = Columns;
  2584. #endif
  2585.     topframe->fr_height = Rows - p_ch;
  2586.     topframe->fr_win = curwin;
  2587.     curwin->w_frame = topframe;
  2588. }
  2589.  
  2590. #if defined(FEAT_WINDOWS) || defined(PROTO)
  2591.  
  2592. /*
  2593.  * Go to another window.
  2594.  * When jumping to another buffer, stop Visual mode.  Do this before
  2595.  * changing windows so we can yank the selection into the '*' register.
  2596.  * When jumping to another window on the same buffer, adjust its cursor
  2597.  * position to keep the same Visual area.
  2598.  */
  2599.     void
  2600. win_goto(wp)
  2601.     win_T    *wp;
  2602. {
  2603. #ifdef FEAT_CMDWIN
  2604.     if (cmdwin_type != 0)
  2605.     {
  2606.     beep_flush();
  2607.     return;
  2608.     }
  2609. #endif
  2610. #ifdef FEAT_VISUAL
  2611.     if (wp->w_buffer != curbuf)
  2612.     reset_VIsual_and_resel();
  2613.     else if (VIsual_active)
  2614.     wp->w_cursor = curwin->w_cursor;
  2615. #endif
  2616.  
  2617. #ifdef FEAT_GUI
  2618.     need_mouse_correct = TRUE;
  2619. #endif
  2620.     win_enter(wp, TRUE);
  2621. }
  2622.  
  2623. #if defined(FEAT_PERL) || defined(PROTO)
  2624. /*
  2625.  * Find window number "winnr" (counting top to bottom).
  2626.  */
  2627.     win_T *
  2628. win_find_nr(winnr)
  2629.     int        winnr;
  2630. {
  2631.     win_T    *wp;
  2632.  
  2633. # ifdef FEAT_WINDOWS
  2634.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  2635.     if (--winnr == 0)
  2636.         break;
  2637.     return wp;
  2638. # else
  2639.     return curwin;
  2640. # endif
  2641. }
  2642. #endif
  2643.  
  2644. #ifdef FEAT_VERTSPLIT
  2645. /*
  2646.  * Move to window above or below "count" times.
  2647.  */
  2648.     static void
  2649. win_goto_ver(up, count)
  2650.     int        up;        /* TRUE to go to win above */
  2651.     long    count;
  2652. {
  2653.     frame_T    *fr;
  2654.     frame_T    *nfr;
  2655.     frame_T    *foundfr;
  2656.  
  2657.     foundfr = curwin->w_frame;
  2658.     while (count--)
  2659.     {
  2660.     /*
  2661.      * First go upwards in the tree of frames until we find a upwards or
  2662.      * downwards neighbor.
  2663.      */
  2664.     fr = foundfr;
  2665.     for (;;)
  2666.     {
  2667.         if (fr == topframe)
  2668.         goto end;
  2669.         if (up)
  2670.         nfr = fr->fr_prev;
  2671.         else
  2672.         nfr = fr->fr_next;
  2673.         if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
  2674.         break;
  2675.         fr = fr->fr_parent;
  2676.     }
  2677.  
  2678.     /*
  2679.      * Now go downwards to find the bottom or top frame in it.
  2680.      */
  2681.     for (;;)
  2682.     {
  2683.         if (nfr->fr_layout == FR_LEAF)
  2684.         {
  2685.         foundfr = nfr;
  2686.         break;
  2687.         }
  2688.         fr = nfr->fr_child;
  2689.         if (nfr->fr_layout == FR_ROW)
  2690.         {
  2691.         /* Find the frame at the cursor row. */
  2692.         while (fr->fr_next != NULL
  2693.             && frame2win(fr)->w_wincol + fr->fr_width
  2694.                      <= curwin->w_wincol + curwin->w_wcol)
  2695.             fr = fr->fr_next;
  2696.         }
  2697.         if (nfr->fr_layout == FR_COL && up)
  2698.         while (fr->fr_next != NULL)
  2699.             fr = fr->fr_next;
  2700.         nfr = fr;
  2701.     }
  2702.     }
  2703. end:
  2704.     if (foundfr != NULL)
  2705.     win_goto(foundfr->fr_win);
  2706. }
  2707.  
  2708. /*
  2709.  * Move to left or right window.
  2710.  */
  2711.     static void
  2712. win_goto_hor(left, count)
  2713.     int        left;        /* TRUE to go to left win */
  2714.     long    count;
  2715. {
  2716.     frame_T    *fr;
  2717.     frame_T    *nfr;
  2718.     frame_T    *foundfr;
  2719.  
  2720.     foundfr = curwin->w_frame;
  2721.     while (count--)
  2722.     {
  2723.     /*
  2724.      * First go upwards in the tree of frames until we find a left or
  2725.      * right neighbor.
  2726.      */
  2727.     fr = foundfr;
  2728.     for (;;)
  2729.     {
  2730.         if (fr == topframe)
  2731.         goto end;
  2732.         if (left)
  2733.         nfr = fr->fr_prev;
  2734.         else
  2735.         nfr = fr->fr_next;
  2736.         if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
  2737.         break;
  2738.         fr = fr->fr_parent;
  2739.     }
  2740.  
  2741.     /*
  2742.      * Now go downwards to find the leftmost or rightmost frame in it.
  2743.      */
  2744.     for (;;)
  2745.     {
  2746.         if (nfr->fr_layout == FR_LEAF)
  2747.         {
  2748.         foundfr = nfr;
  2749.         break;
  2750.         }
  2751.         fr = nfr->fr_child;
  2752.         if (nfr->fr_layout == FR_COL)
  2753.         {
  2754.         /* Find the frame at the cursor row. */
  2755.         while (fr->fr_next != NULL
  2756.             && frame2win(fr)->w_winrow + fr->fr_height
  2757.                      <= curwin->w_winrow + curwin->w_wrow)
  2758.             fr = fr->fr_next;
  2759.         }
  2760.         if (nfr->fr_layout == FR_ROW && left)
  2761.         while (fr->fr_next != NULL)
  2762.             fr = fr->fr_next;
  2763.         nfr = fr;
  2764.     }
  2765.     }
  2766. end:
  2767.     if (foundfr != NULL)
  2768.     win_goto(foundfr->fr_win);
  2769. }
  2770. #endif
  2771.  
  2772. /*
  2773.  * Make window "wp" the current window.
  2774.  */
  2775.     void
  2776. win_enter(wp, undo_sync)
  2777.     win_T    *wp;
  2778.     int        undo_sync;
  2779. {
  2780.     win_enter_ext(wp, undo_sync, FALSE);
  2781. }
  2782.  
  2783. /*
  2784.  * Make window wp the current window.
  2785.  * Can be called with "curwin_invalid" TRUE, which means that curwin has just
  2786.  * been closed and isn't valid.
  2787.  */
  2788.     static void
  2789. win_enter_ext(wp, undo_sync, curwin_invalid)
  2790.     win_T    *wp;
  2791.     int        undo_sync;
  2792.     int        curwin_invalid;
  2793. {
  2794. #ifdef FEAT_AUTOCMD
  2795.     int        other_buffer = FALSE;
  2796. #endif
  2797.  
  2798.     if (wp == curwin && !curwin_invalid)    /* nothing to do */
  2799.     return;
  2800.  
  2801. #ifdef FEAT_AUTOCMD
  2802.     if (!curwin_invalid)
  2803.     {
  2804.     /*
  2805.      * Be careful: If autocommands delete the window, return now.
  2806.      */
  2807.     if (wp->w_buffer != curbuf)
  2808.     {
  2809.         apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
  2810.         other_buffer = TRUE;
  2811.         if (!win_valid(wp))
  2812.         return;
  2813.     }
  2814.     apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
  2815.     if (!win_valid(wp))
  2816.         return;
  2817.     }
  2818. #endif
  2819.  
  2820.     /* sync undo before leaving the current buffer */
  2821.     if (undo_sync && curbuf != wp->w_buffer)
  2822.     u_sync();
  2823.     /* may have to copy the buffer options when 'cpo' contains 'S' */
  2824.     if (wp->w_buffer != curbuf)
  2825.     buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
  2826.     if (!curwin_invalid)
  2827.     {
  2828.     prevwin = curwin;    /* remember for CTRL-W p */
  2829.     curwin->w_redr_status = TRUE;
  2830.     }
  2831.     curwin = wp;
  2832.     curbuf = wp->w_buffer;
  2833.     check_cursor();
  2834. #ifdef FEAT_VIRTUALEDIT
  2835.     if (!virtual_active())
  2836.     curwin->w_cursor.coladd = 0;
  2837. #endif
  2838.     changed_line_abv_curs();    /* assume cursor position needs updating */
  2839.  
  2840.     if (curwin->w_localdir != NULL)
  2841.     {
  2842.     /* Window has a local directory: Save current directory as global
  2843.      * directory (unless that was done already) and change to the local
  2844.      * directory. */
  2845.     if (globaldir == NULL)
  2846.     {
  2847.         char_u    cwd[MAXPATHL];
  2848.  
  2849.         if (mch_dirname(cwd, MAXPATHL) == OK)
  2850.         globaldir = vim_strsave(cwd);
  2851.     }
  2852.     mch_chdir((char *)curwin->w_localdir);
  2853.     shorten_fnames(TRUE);
  2854.     }
  2855.     else if (globaldir != NULL)
  2856.     {
  2857.     /* Window doesn't have a local directory and we are not in the global
  2858.      * directory: Change to the global directory. */
  2859.     mch_chdir((char *)globaldir);
  2860.     vim_free(globaldir);
  2861.     globaldir = NULL;
  2862.     shorten_fnames(TRUE);
  2863.     }
  2864.  
  2865. #ifdef FEAT_AUTOCMD
  2866.     apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
  2867.     if (other_buffer)
  2868.     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  2869. #endif
  2870.  
  2871. #ifdef FEAT_TITLE
  2872.     maketitle();
  2873. #endif
  2874.     curwin->w_redr_status = TRUE;
  2875.     if (restart_edit)
  2876.     redraw_later(VALID);    /* causes status line redraw */
  2877.  
  2878.     /* set window height to desired minimal value */
  2879.     if (curwin->w_height < p_wh)
  2880.     win_setheight((int)p_wh);
  2881.  
  2882. #ifdef FEAT_VERTSPLIT
  2883.     /* set window width to desired minimal value */
  2884.     if (curwin->w_width < p_wiw)
  2885.     win_setwidth((int)p_wiw);
  2886. #endif
  2887.  
  2888. #ifdef FEAT_MOUSE
  2889.     setmouse();            /* in case jumped to/from help buffer */
  2890. #endif
  2891. }
  2892.  
  2893. #endif /* FEAT_WINDOWS */
  2894.  
  2895. #if defined(FEAT_WINDOWS) || defined(FEAT_SIGNS) || defined(PROTO)
  2896. /*
  2897.  * Jump to the first open window that contains buffer buf if one exists
  2898.  * TODO: Alternatively jump to last open window? Dependent from 'splitbelow'?
  2899.  * Returns pointer to window if it exists, otherwise NULL.
  2900.  */
  2901.     win_T *
  2902. buf_jump_open_win(buf)
  2903.     buf_T    *buf;
  2904. {
  2905. # ifdef FEAT_WINDOWS
  2906.     win_T    *wp;
  2907.  
  2908.     for (wp = firstwin; wp; wp = wp->w_next)
  2909.     if (wp->w_buffer == buf)
  2910.         break;
  2911.     if (wp != NULL)
  2912.     win_enter(wp, FALSE);
  2913.     return wp;
  2914. # else
  2915.     if (curwin->w_buffer == buf)
  2916.     return curwin;
  2917.     return NULL;
  2918. # endif
  2919. }
  2920. #endif
  2921.  
  2922. /*
  2923.  * allocate a window structure and link it in the window list
  2924.  */
  2925. /*ARGSUSED*/
  2926.     static win_T *
  2927. win_alloc(after)
  2928.     win_T    *after;
  2929. {
  2930.     win_T    *newwin;
  2931.  
  2932.     /*
  2933.      * allocate window structure and linesizes arrays
  2934.      */
  2935.     newwin = (win_T *)alloc_clear((unsigned)sizeof(win_T));
  2936.     if (newwin != NULL && win_alloc_lines(newwin) == FAIL)
  2937.     {
  2938.     vim_free(newwin);
  2939.     newwin = NULL;
  2940.     }
  2941.  
  2942.     if (newwin != NULL)
  2943.     {
  2944.     /*
  2945.      * link the window in the window list
  2946.      */
  2947. #ifdef FEAT_WINDOWS
  2948.     win_append(after, newwin);
  2949. #endif
  2950. #ifdef FEAT_VERTSPLIT
  2951.     newwin->w_wincol = 0;
  2952.     newwin->w_width = Columns;
  2953. #endif
  2954.  
  2955.     /* position the display and the cursor at the top of the file. */
  2956.     newwin->w_topline = 1;
  2957. #ifdef FEAT_DIFF
  2958.     newwin->w_topfill = 0;
  2959. #endif
  2960.     newwin->w_botline = 2;
  2961.     newwin->w_cursor.lnum = 1;
  2962. #ifdef FEAT_SCROLLBIND
  2963.     newwin->w_scbind_pos = 1;
  2964. #endif
  2965.  
  2966.     /* We won't calculate w_fraction until resizing the window */
  2967.     newwin->w_fraction = 0;
  2968.     newwin->w_prev_fraction_row = -1;
  2969.  
  2970. #ifdef FEAT_GUI
  2971.     if (gui.in_use)
  2972.     {
  2973.         gui_create_scrollbar(&newwin->w_scrollbars[SBAR_LEFT],
  2974.             SBAR_LEFT, newwin);
  2975.         gui_create_scrollbar(&newwin->w_scrollbars[SBAR_RIGHT],
  2976.             SBAR_RIGHT, newwin);
  2977.     }
  2978. #endif
  2979. #ifdef FEAT_EVAL
  2980.     var_init(&newwin->w_vars);        /* init internal variables */
  2981. #endif
  2982. #ifdef FEAT_FOLDING
  2983.     foldInitWin(newwin);
  2984. #endif
  2985.     }
  2986.     return newwin;
  2987. }
  2988.  
  2989. #if defined(FEAT_WINDOWS) || defined(PROTO)
  2990.  
  2991. /*
  2992.  * remove window 'wp' from the window list and free the structure
  2993.  */
  2994.     static void
  2995. win_free(wp)
  2996.     win_T    *wp;
  2997. {
  2998.     int        i;
  2999.  
  3000. #ifdef FEAT_PERL
  3001.     perl_win_free(wp);
  3002. #endif
  3003.  
  3004. #ifdef FEAT_PYTHON
  3005.     python_window_free(wp);
  3006. #endif
  3007.  
  3008. #ifdef FEAT_TCL
  3009.     tcl_window_free(wp);
  3010. #endif
  3011.  
  3012. #ifdef FEAT_RUBY
  3013.     ruby_window_free(wp);
  3014. #endif
  3015.  
  3016.     clear_winopt(&wp->w_onebuf_opt);
  3017.     clear_winopt(&wp->w_allbuf_opt);
  3018.  
  3019. #ifdef FEAT_EVAL
  3020.     var_clear(&wp->w_vars);        /* free all internal variables */
  3021. #endif
  3022.  
  3023.     if (prevwin == wp)
  3024.     prevwin = NULL;
  3025.     win_free_lsize(wp);
  3026.  
  3027.     for (i = 0; i < wp->w_tagstacklen; ++i)
  3028.     vim_free(wp->w_tagstack[i].tagname);
  3029.  
  3030.     vim_free(wp->w_localdir);
  3031. #ifdef FEAT_SEARCH_EXTRA
  3032.     vim_free(wp->w_match.regprog);
  3033. #endif
  3034. #ifdef FEAT_JUMPLIST
  3035.     free_jumplist(wp);
  3036. #endif
  3037.  
  3038. #ifdef FEAT_GUI
  3039.     if (gui.in_use)
  3040.     {
  3041.     gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
  3042.     gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
  3043.     }
  3044. #endif /* FEAT_GUI */
  3045.  
  3046.     win_remove(wp);
  3047.     vim_free(wp);
  3048. }
  3049.  
  3050. /*
  3051.  * Append window "wp" in the window list after window "after".
  3052.  */
  3053.     static void
  3054. win_append(after, wp)
  3055.     win_T    *after, *wp;
  3056. {
  3057.     win_T    *before;
  3058.  
  3059.     if (after == NULL)        /* after NULL is in front of the first */
  3060.     before = firstwin;
  3061.     else
  3062.     before = after->w_next;
  3063.  
  3064.     wp->w_next = before;
  3065.     wp->w_prev = after;
  3066.     if (after == NULL)
  3067.     firstwin = wp;
  3068.     else
  3069.     after->w_next = wp;
  3070.     if (before == NULL)
  3071.     lastwin = wp;
  3072.     else
  3073.     before->w_prev = wp;
  3074. }
  3075.  
  3076. /*
  3077.  * Remove a window from the window list.
  3078.  */
  3079.     static void
  3080. win_remove(wp)
  3081.     win_T    *wp;
  3082. {
  3083.     if (wp->w_prev != NULL)
  3084.     wp->w_prev->w_next = wp->w_next;
  3085.     else
  3086.     firstwin = wp->w_next;
  3087.     if (wp->w_next != NULL)
  3088.     wp->w_next->w_prev = wp->w_prev;
  3089.     else
  3090.     lastwin = wp->w_prev;
  3091. }
  3092.  
  3093. /*
  3094.  * Append frame "frp" in a frame list after frame "after".
  3095.  */
  3096.     static void
  3097. frame_append(after, frp)
  3098.     frame_T    *after, *frp;
  3099. {
  3100.     frp->fr_next = after->fr_next;
  3101.     after->fr_next = frp;
  3102.     if (frp->fr_next != NULL)
  3103.     frp->fr_next->fr_prev = frp;
  3104.     frp->fr_prev = after;
  3105. }
  3106.  
  3107. /*
  3108.  * Insert frame "frp" in a frame list before frame "before".
  3109.  */
  3110.     static void
  3111. frame_insert(before, frp)
  3112.     frame_T    *before, *frp;
  3113. {
  3114.     frp->fr_next = before;
  3115.     frp->fr_prev = before->fr_prev;
  3116.     before->fr_prev = frp;
  3117.     if (frp->fr_prev != NULL)
  3118.     frp->fr_prev->fr_next = frp;
  3119.     else
  3120.     frp->fr_parent->fr_child = frp;
  3121. }
  3122.  
  3123. /*
  3124.  * Remove a frame from a frame list.
  3125.  */
  3126.     static void
  3127. frame_remove(frp)
  3128.     frame_T    *frp;
  3129. {
  3130.     if (frp->fr_prev != NULL)
  3131.     frp->fr_prev->fr_next = frp->fr_next;
  3132.     else
  3133.     frp->fr_parent->fr_child = frp->fr_next;
  3134.     if (frp->fr_next != NULL)
  3135.     frp->fr_next->fr_prev = frp->fr_prev;
  3136. }
  3137.  
  3138. #endif /* FEAT_WINDOWS */
  3139.  
  3140. /*
  3141.  * Allocate w_lines[] for window "wp".
  3142.  * Return FAIL for failure, OK for success.
  3143.  */
  3144.     int
  3145. win_alloc_lines(wp)
  3146.     win_T    *wp;
  3147. {
  3148.     wp->w_lines_valid = 0;
  3149.     wp->w_lines = (wline_T *)alloc((unsigned)(Rows * sizeof(wline_T)));
  3150.     if (wp->w_lines == NULL)
  3151.     return FAIL;
  3152.     return OK;
  3153. }
  3154.  
  3155. /*
  3156.  * free lsize arrays for a window
  3157.  */
  3158.     void
  3159. win_free_lsize(wp)
  3160.     win_T    *wp;
  3161. {
  3162.     vim_free(wp->w_lines);
  3163.     wp->w_lines = NULL;
  3164. }
  3165.  
  3166. /*
  3167.  * Called from win_new_shellsize() after Rows changed.
  3168.  */
  3169.     void
  3170. shell_new_rows()
  3171. {
  3172.     int        h = (int)(Rows - p_ch);
  3173.  
  3174.     if (firstwin == NULL)    /* not initialized yet */
  3175.     return;
  3176. #ifdef FEAT_WINDOWS
  3177.     if (h < frame_minheight(topframe, NULL))
  3178.     h = frame_minheight(topframe, NULL);
  3179.     frame_new_height(topframe, h, FALSE);
  3180.     (void)win_comp_pos();        /* recompute w_winrow and w_wincol */
  3181. #else
  3182.     if (h < 1)
  3183.     h = 1;
  3184.     win_new_height(firstwin, h);
  3185. #endif
  3186.     compute_cmdrow();
  3187. #if 0
  3188.     /* Disabled: don't want making the screen smaller make a window larger. */
  3189.     if (p_ea)
  3190.     win_equal(curwin, 'v');
  3191. #endif
  3192. }
  3193.  
  3194. #if defined(FEAT_VERTSPLIT) || defined(PROTO)
  3195. /*
  3196.  * Called from win_new_shellsize() after Columns changed.
  3197.  */
  3198.     void
  3199. shell_new_columns()
  3200. {
  3201.     if (firstwin == NULL)    /* not initialized yet */
  3202.     return;
  3203.     frame_new_width(topframe, (int)Columns, FALSE);
  3204.     (void)win_comp_pos();        /* recompute w_winrow and w_wincol */
  3205. #if 0
  3206.     /* Disabled: don't want making the screen smaller make a window larger. */
  3207.     if (p_ea)
  3208.     win_equal(curwin, 'h');
  3209. #endif
  3210. }
  3211. #endif
  3212.  
  3213. #if defined(FEAT_CMDWIN) || defined(PROTO)
  3214. /*
  3215.  * Save the size of all windows in "gap".
  3216.  */
  3217.     void
  3218. win_size_save(gap)
  3219.     garray_T    *gap;
  3220.  
  3221. {
  3222.     win_T    *wp;
  3223.  
  3224.     ga_init2(gap, (int)sizeof(int), 1);
  3225.     if (ga_grow(gap, win_count() * 2) == OK)
  3226.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3227.     {
  3228.         ((int *)gap->ga_data)[gap->ga_len++] =
  3229.                            wp->w_width + wp->w_vsep_width;
  3230.         ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
  3231.     }
  3232. }
  3233.  
  3234. /*
  3235.  * Restore window sizes, but only if the number of windows is still the same.
  3236.  * Does not free the growarray.
  3237.  */
  3238.     void
  3239. win_size_restore(gap)
  3240.     garray_T    *gap;
  3241. {
  3242.     win_T    *wp;
  3243.     int        i;
  3244.  
  3245.     if (win_count() * 2 == gap->ga_len)
  3246.     {
  3247.     i = 0;
  3248.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3249.     {
  3250.         frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
  3251.         win_setheight_win(((int *)gap->ga_data)[i++], wp);
  3252.     }
  3253.     /* recompute the window positions */
  3254.     (void)win_comp_pos();
  3255.     }
  3256. }
  3257. #endif /* FEAT_CMDWIN */
  3258.  
  3259. #if defined(FEAT_WINDOWS) || defined(PROTO)
  3260. /*
  3261.  * Update the position for all windows, using the width and height of the
  3262.  * frames.
  3263.  * Returns the row just after the last window.
  3264.  */
  3265.     static int
  3266. win_comp_pos()
  3267. {
  3268.     int        row = 0;
  3269.     int        col = 0;
  3270.  
  3271.     frame_comp_pos(topframe, &row, &col);
  3272.     return row;
  3273. }
  3274.  
  3275. /*
  3276.  * Update the position of the windows in frame "topfrp", using the width and
  3277.  * height of the frames.
  3278.  * "*row" and "*col" are the top-left position of the frame.  They are updated
  3279.  * to the bottom-right position plus one.
  3280.  */
  3281.     static void
  3282. frame_comp_pos(topfrp, row, col)
  3283.     frame_T    *topfrp;
  3284.     int        *row;
  3285.     int        *col;
  3286. {
  3287.     win_T    *wp;
  3288.     frame_T    *frp;
  3289. #ifdef FEAT_VERTSPLIT
  3290.     int        startcol;
  3291.     int        startrow;
  3292. #endif
  3293.  
  3294.     wp = topfrp->fr_win;
  3295.     if (wp != NULL)
  3296.     {
  3297.     if (wp->w_winrow != *row
  3298. #ifdef FEAT_VERTSPLIT
  3299.         || wp->w_wincol != *col
  3300. #endif
  3301.         )
  3302.     {
  3303.         /* position changed, redraw */
  3304.         wp->w_winrow = *row;
  3305. #ifdef FEAT_VERTSPLIT
  3306.         wp->w_wincol = *col;
  3307. #endif
  3308.         redraw_win_later(wp, NOT_VALID);
  3309.         wp->w_redr_status = TRUE;
  3310.     }
  3311.     *row += wp->w_height + wp->w_status_height;
  3312. #ifdef FEAT_VERTSPLIT
  3313.     *col += wp->w_width + wp->w_vsep_width;
  3314. #endif
  3315.     }
  3316.     else
  3317.     {
  3318. #ifdef FEAT_VERTSPLIT
  3319.     startrow = *row;
  3320.     startcol = *col;
  3321. #endif
  3322.     for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
  3323.     {
  3324. #ifdef FEAT_VERTSPLIT
  3325.         if (topfrp->fr_layout == FR_ROW)
  3326.         *row = startrow;    /* all frames are at the same row */
  3327.         else
  3328.         *col = startcol;    /* all frames are at the same col */
  3329. #endif
  3330.         frame_comp_pos(frp, row, col);
  3331.     }
  3332.     }
  3333. }
  3334.  
  3335. #endif /* FEAT_WINDOWS */
  3336.  
  3337. /*
  3338.  * Set current window height and take care of repositioning other windows to
  3339.  * fit around it.
  3340.  */
  3341.     void
  3342. win_setheight(height)
  3343.     int        height;
  3344. {
  3345.     /* Always keep current window at least one line high, even when
  3346.      * 'winminheight' is zero. */
  3347. #ifdef FEAT_WINDOWS
  3348.     if (height < p_wmh)
  3349.     height = p_wmh;
  3350. #endif
  3351.     if (height == 0)
  3352.     height = 1;
  3353.     win_setheight_win(height, curwin);
  3354. }
  3355.  
  3356. /*
  3357.  * Set the window height of window "win" and take care of repositioning other
  3358.  * windows to fit around it.
  3359.  */
  3360.     static void
  3361. win_setheight_win(height, win)
  3362.     int        height;
  3363.     win_T    *win;
  3364. {
  3365.     int        row;
  3366.  
  3367. #ifdef FEAT_WINDOWS
  3368.     frame_setheight(win->w_frame, height + win->w_status_height);
  3369.  
  3370.     /* recompute the window positions */
  3371.     row = win_comp_pos();
  3372. #else
  3373.     if (height > topframe->fr_height)
  3374.     height = topframe->fr_height;
  3375.     win->w_height = height;
  3376.     row = height;
  3377. #endif
  3378.  
  3379.     /*
  3380.      * If there is extra space created between the last window and the command
  3381.      * line, clear it.
  3382.      */
  3383.     if (full_screen && msg_scrolled == 0 && row < cmdline_row)
  3384.     screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
  3385.     cmdline_row = row;
  3386.     msg_row = row;
  3387.     msg_col = 0;
  3388.  
  3389.     redraw_all_later(NOT_VALID);
  3390. }
  3391.  
  3392. #if defined(FEAT_WINDOWS) || defined(PROTO)
  3393.  
  3394. /*
  3395.  * Set the height of a frame to "height" and take care that all frames and
  3396.  * windows inside it are resized.  Also resize frames on the left and right if
  3397.  * the are in the same FR_ROW frame.
  3398.  *
  3399.  * Strategy:
  3400.  * If the frame is part of a FR_COL frame, try fitting the frame in that
  3401.  * frame.  If that doesn't work (the FR_COL frame is too small), recursively
  3402.  * go to containing frames to resize them and make room.
  3403.  * If the frame is part of a FR_ROW frame, all frames must be resized as well.
  3404.  * Check for the minimal height of the FR_ROW frame.
  3405.  * At the top level we can also use change the command line height.
  3406.  */
  3407.     static void
  3408. frame_setheight(curfrp, height)
  3409.     frame_T    *curfrp;
  3410.     int        height;
  3411. {
  3412.     int        room;        /* total number of lines available */
  3413.     int        take;        /* number of lines taken from other windows */
  3414.     int        room_cmdline;    /* lines available from cmdline */
  3415.     int        run;
  3416.     frame_T    *frp;
  3417.     int        h;
  3418. #ifdef FEAT_QUICKFIX
  3419.     int        room_reserved;
  3420. #endif
  3421.  
  3422.     /* If the height already is the desired value, nothing to do. */
  3423.     if (curfrp->fr_height == height)
  3424.     return;
  3425.  
  3426.     if (curfrp->fr_parent == NULL)
  3427.     {
  3428.     /* topframe: can only change the command line */
  3429.     if (height > Rows - p_ch)
  3430.         height = Rows - p_ch;
  3431.     if (height > 0)
  3432.         frame_new_height(curfrp, height, FALSE);
  3433.     }
  3434.     else if (curfrp->fr_parent->fr_layout == FR_ROW)
  3435.     {
  3436.     /* Row of frames: Also need to resize frames left and right of this
  3437.      * one.  First check for the minimal height of these. */
  3438.     h = frame_minheight(curfrp->fr_parent, NULL);
  3439.     if (height < h)
  3440.         height = h;
  3441.     frame_setheight(curfrp->fr_parent, height);
  3442.     }
  3443.     else
  3444.     {
  3445.     /*
  3446.      * Column of frames: try to change only frames in this column.
  3447.      */
  3448. #ifdef FEAT_VERTSPLIT
  3449.     /*
  3450.      * Do this twice:
  3451.      * 1: compute room available, if it's not enough try resizing the
  3452.      *    containing frame.
  3453.      * 2: compute the room available and adjust the height to it.
  3454.      * Try not to reduce the height of the quickfix and preview window.
  3455.      */
  3456.     for (run = 1; run <= 2; ++run)
  3457. #else
  3458.     for (;;)
  3459. #endif
  3460.     {
  3461.         room = 0;
  3462. #ifdef FEAT_QUICKFIX
  3463.         room_reserved = 0;
  3464. #endif
  3465.         for (frp = curfrp->fr_parent->fr_child; frp != NULL;
  3466.                                frp = frp->fr_next)
  3467.         {
  3468. #ifdef FEAT_QUICKFIX
  3469.         if (frp != curfrp
  3470.             && frp->fr_win != NULL
  3471.             && (frp->fr_win->w_p_pvw
  3472.                 || bt_quickfix(frp->fr_win->w_buffer)))
  3473.             room_reserved += frp->fr_height;
  3474. #endif
  3475.         room += frp->fr_height;
  3476.         if (frp != curfrp)
  3477.             room -= frame_minheight(frp, NULL);
  3478.         }
  3479. #ifdef FEAT_VERTSPLIT
  3480.         if (curfrp->fr_width != Columns)
  3481.         room_cmdline = 0;
  3482.         else
  3483. #endif
  3484.         {
  3485.         room_cmdline = Rows - p_ch - (lastwin->w_winrow
  3486.                    + lastwin->w_height + lastwin->w_status_height);
  3487.         if (room_cmdline < 0)
  3488.             room_cmdline = 0;
  3489.         }
  3490.  
  3491.         if (height <= room + room_cmdline)
  3492.         break;
  3493. #ifdef FEAT_VERTSPLIT
  3494.         if (run == 2 || curfrp->fr_width == Columns)
  3495. #endif
  3496.         {
  3497.         if (height > room + room_cmdline)
  3498.             height = room + room_cmdline;
  3499.         break;
  3500.         }
  3501. #ifdef FEAT_VERTSPLIT
  3502.         frame_setheight(curfrp->fr_parent, height
  3503.         + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
  3504. #endif
  3505.         /*NOTREACHED*/
  3506.     }
  3507.  
  3508.     /*
  3509.      * Compute the number of lines we will take from others frames (can be
  3510.      * negative!).
  3511.      */
  3512.     take = height - curfrp->fr_height;
  3513.  
  3514. #ifdef FEAT_QUICKFIX
  3515.     /* If there is not enough room, also reduce the height of quickfix and
  3516.      * preview window. */
  3517.     if (height > room + room_cmdline - room_reserved)
  3518.         room_reserved = room + room_cmdline - height;
  3519.     /* If there is only a quickfix or preview window and making the
  3520.      * window smaller, need to make the other window taller. */
  3521.     if (take < 0 && room - curfrp->fr_height < room_reserved)
  3522.         room_reserved = 0;
  3523. #endif
  3524.  
  3525.     if (take > 0 && room_cmdline > 0)
  3526.     {
  3527.         /* use lines from cmdline first */
  3528.         if (take < room_cmdline)
  3529.         room_cmdline = take;
  3530.         take -= room_cmdline;
  3531.         topframe->fr_height += room_cmdline;
  3532.     }
  3533.  
  3534.     /*
  3535.      * set the current frame to the new height
  3536.      */
  3537.     frame_new_height(curfrp, height, FALSE);
  3538.  
  3539.     /*
  3540.      * First take lines from the frames after the current frame.  If
  3541.      * that is not enough, takes lines from frames above the current
  3542.      * frame.
  3543.      */
  3544.     for (run = 0; run < 2; ++run)
  3545.     {
  3546.         if (run == 0)
  3547.         frp = curfrp->fr_next;    /* 1st run: start with next window */
  3548.         else
  3549.         frp = curfrp->fr_prev;    /* 2nd run: start with prev window */
  3550.         while (frp != NULL && take != 0)
  3551.         {
  3552.         h = frame_minheight(frp, NULL);
  3553. #ifdef FEAT_QUICKFIX
  3554.         if (room_reserved > 0
  3555.             && frp->fr_win != NULL
  3556.             && (frp->fr_win->w_p_pvw
  3557.                 || bt_quickfix(frp->fr_win->w_buffer)))
  3558.         {
  3559.             if (room_reserved >= frp->fr_height)
  3560.             room_reserved -= frp->fr_height;
  3561.             else
  3562.             {
  3563.             if (frp->fr_height - room_reserved > take)
  3564.                 room_reserved = frp->fr_height - take;
  3565.             take -= frp->fr_height - room_reserved;
  3566.             frame_new_height(frp, room_reserved, FALSE);
  3567.             room_reserved = 0;
  3568.             }
  3569.         }
  3570.         else
  3571. #endif
  3572.         {
  3573.             if (frp->fr_height - take < h)
  3574.             {
  3575.             take -= frp->fr_height - h;
  3576.             frame_new_height(frp, h, FALSE);
  3577.             }
  3578.             else
  3579.             {
  3580.             frame_new_height(frp, frp->fr_height - take, FALSE);
  3581.             take = 0;
  3582.             }
  3583.         }
  3584.         if (run == 0)
  3585.             frp = frp->fr_next;
  3586.         else
  3587.             frp = frp->fr_prev;
  3588.         }
  3589.     }
  3590.     }
  3591. }
  3592.  
  3593. #if defined(FEAT_VERTSPLIT) || defined(PROTO)
  3594. /*
  3595.  * Set current window width and take care of repositioning other windows to
  3596.  * fit around it.
  3597.  */
  3598.     void
  3599. win_setwidth(width)
  3600.     int        width;
  3601. {
  3602.     /* Always keep current window at least one column wide, even when
  3603.      * 'winminwidth' is zero. */
  3604.     if (width < p_wmw)
  3605.     width = p_wmw;
  3606.     if (width == 0)
  3607.     width = 1;
  3608.  
  3609.     frame_setwidth(curwin->w_frame, width + curwin->w_vsep_width);
  3610.  
  3611.     /* recompute the window positions */
  3612.     (void)win_comp_pos();
  3613.  
  3614.     redraw_all_later(NOT_VALID);
  3615. }
  3616.  
  3617. /*
  3618.  * Set the width of a frame to "width" and take care that all frames and
  3619.  * windows inside it are resized.  Also resize frames above and below if the
  3620.  * are in the same FR_ROW frame.
  3621.  *
  3622.  * Strategy is similar to frame_setheight().
  3623.  */
  3624.     static void
  3625. frame_setwidth(curfrp, width)
  3626.     frame_T    *curfrp;
  3627.     int        width;
  3628. {
  3629.     int        room;        /* total number of lines available */
  3630.     int        take;        /* number of lines taken from other windows */
  3631.     int        run;
  3632.     frame_T    *frp;
  3633.     int        w;
  3634.  
  3635.     /* If the width already is the desired value, nothing to do. */
  3636.     if (curfrp->fr_width == width)
  3637.     return;
  3638.  
  3639.     if (curfrp->fr_parent == NULL)
  3640.     /* topframe: can't change width */
  3641.     return;
  3642.  
  3643.     if (curfrp->fr_parent->fr_layout == FR_COL)
  3644.     {
  3645.     /* Column of frames: Also need to resize frames above and below of
  3646.      * this one.  First check for the minimal width of these. */
  3647.     w = frame_minwidth(curfrp->fr_parent, NULL);
  3648.     if (width < w)
  3649.         width = w;
  3650.     frame_setwidth(curfrp->fr_parent, width);
  3651.     }
  3652.     else
  3653.     {
  3654.     /*
  3655.      * Row of frames: try to change only frames in this row.
  3656.      *
  3657.      * Do this twice:
  3658.      * 1: compute room available, if it's not enough try resizing the
  3659.      *    containing frame.
  3660.      * 2: compute the room available and adjust the width to it.
  3661.      */
  3662.     for (run = 1; run <= 2; ++run)
  3663.     {
  3664.         room = 0;
  3665.         for (frp = curfrp->fr_parent->fr_child; frp != NULL;
  3666.                                frp = frp->fr_next)
  3667.         {
  3668.         room += frp->fr_width;
  3669.         if (frp != curfrp)
  3670.             room -= frame_minwidth(frp, NULL);
  3671.         }
  3672.  
  3673.         if (width <= room)
  3674.         break;
  3675.         if (run == 2 || curfrp->fr_height >= Rows - p_ch)
  3676.         {
  3677.         if (width > room)
  3678.             width = room;
  3679.         break;
  3680.         }
  3681.         frame_setwidth(curfrp->fr_parent, width
  3682.          + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
  3683.     }
  3684.  
  3685.  
  3686.     /*
  3687.      * Compute the number of lines we will take from others frames (can be
  3688.      * negative!).
  3689.      */
  3690.     take = width - curfrp->fr_width;
  3691.  
  3692.     /*
  3693.      * set the current frame to the new width
  3694.      */
  3695.     frame_new_width(curfrp, width, FALSE);
  3696.  
  3697.     /*
  3698.      * First take lines from the frames right of the current frame.  If
  3699.      * that is not enough, takes lines from frames left of the current
  3700.      * frame.
  3701.      */
  3702.     for (run = 0; run < 2; ++run)
  3703.     {
  3704.         if (run == 0)
  3705.         frp = curfrp->fr_next;    /* 1st run: start with next window */
  3706.         else
  3707.         frp = curfrp->fr_prev;    /* 2nd run: start with prev window */
  3708.         while (frp != NULL && take != 0)
  3709.         {
  3710.         w = frame_minwidth(frp, NULL);
  3711.         if (frp->fr_width - take < w)
  3712.         {
  3713.             take -= frp->fr_width - w;
  3714.             frame_new_width(frp, w, FALSE);
  3715.         }
  3716.         else
  3717.         {
  3718.             frame_new_width(frp, frp->fr_width - take, FALSE);
  3719.             take = 0;
  3720.         }
  3721.         if (run == 0)
  3722.             frp = frp->fr_next;
  3723.         else
  3724.             frp = frp->fr_prev;
  3725.         }
  3726.     }
  3727.     }
  3728. }
  3729. #endif /* FEAT_VERTSPLIT */
  3730.  
  3731. /*
  3732.  * Check 'winminheight' for a valid value.
  3733.  */
  3734.     void
  3735. win_setminheight()
  3736. {
  3737.     int        room;
  3738.     int        first = TRUE;
  3739.     win_T    *wp;
  3740.  
  3741.     /* loop until there is a 'winminheight' that is possible */
  3742.     while (p_wmh > 0)
  3743.     {
  3744.     /* TODO: handle vertical splits */
  3745.     room = -p_wh;
  3746.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3747.         room += wp->w_height - p_wmh;
  3748.     if (room >= 0)
  3749.         break;
  3750.     --p_wmh;
  3751.     if (first)
  3752.     {
  3753.         EMSG(_(e_noroom));
  3754.         first = FALSE;
  3755.     }
  3756.     }
  3757. }
  3758.  
  3759. #ifdef FEAT_MOUSE
  3760.  
  3761. /*
  3762.  * Status line of curwin is dragged "offset" lines down (negative is up).
  3763.  */
  3764.     void
  3765. win_drag_status_line(offset)
  3766.     int        offset;
  3767. {
  3768.     frame_T    *curfr;
  3769.     frame_T    *fr;
  3770.     int        room;
  3771.     int        row;
  3772.     int        up;    /* if TRUE, drag status line up, otherwise down */
  3773.     int        n;
  3774.  
  3775.     fr = curwin->w_frame;
  3776.     curfr = fr;
  3777.     if (fr != topframe)        /* more than one window */
  3778.     {
  3779.     fr = fr->fr_parent;
  3780.     /* When the parent frame is not a column of frames, its parent should
  3781.      * be. */
  3782.     if (fr->fr_layout != FR_COL)
  3783.     {
  3784.         curfr = fr;
  3785.         if (fr != topframe)    /* only a row of windows, may drag statusline */
  3786.         fr = fr->fr_parent;
  3787.     }
  3788.     }
  3789.  
  3790.     /* If this is the last frame in a column, may want to resize the parent
  3791.      * frame instead (go two up to skip a row of frames). */
  3792.     while (curfr != topframe && curfr->fr_next == NULL)
  3793.     {
  3794.     if (fr != topframe)
  3795.         fr = fr->fr_parent;
  3796.     curfr = fr;
  3797.     if (fr != topframe)
  3798.         fr = fr->fr_parent;
  3799.     }
  3800.  
  3801.     if (offset < 0) /* drag up */
  3802.     {
  3803.     up = TRUE;
  3804.     offset = -offset;
  3805.     /* sum up the room of the current frame and above it */
  3806.     if (fr == curfr)
  3807.     {
  3808.         /* only one window */
  3809.         room = fr->fr_height - frame_minheight(fr, NULL);
  3810.     }
  3811.     else
  3812.     {
  3813.         room = 0;
  3814.         for (fr = fr->fr_child; ; fr = fr->fr_next)
  3815.         {
  3816.         room += fr->fr_height - frame_minheight(fr, NULL);
  3817.         if (fr == curfr)
  3818.             break;
  3819.         }
  3820.     }
  3821.     fr = curfr->fr_next;        /* put fr at frame that grows */
  3822.     }
  3823.     else    /* drag down */
  3824.     {
  3825.     up = FALSE;
  3826.     /*
  3827.      * Only dragging the last status line can reduce p_ch.
  3828.      */
  3829.     room = Rows - cmdline_row;
  3830.     if (curfr->fr_next == NULL)
  3831.         room -= 1;
  3832.     else
  3833.         room -= p_ch;
  3834.     if (room < 0)
  3835.         room = 0;
  3836.     /* sum up the room of frames below of the current one */
  3837.     for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
  3838.         room += fr->fr_height - frame_minheight(fr, NULL);
  3839.     fr = curfr;            /* put fr at window that grows */
  3840.     }
  3841.  
  3842.     if (room < offset)        /* Not enough room */
  3843.     offset = room;        /* Move as far as we can */
  3844.     if (offset <= 0)
  3845.     return;
  3846.  
  3847.     /*
  3848.      * Grow frame fr by "offset" lines.
  3849.      * Doesn't happen when dragging the last status line up.
  3850.      */
  3851.     if (fr != NULL)
  3852.     frame_new_height(fr, fr->fr_height + offset, up);
  3853.  
  3854.     if (up)
  3855.     fr = curfr;        /* current frame gets smaller */
  3856.     else
  3857.     fr = curfr->fr_next;    /* next frame gets smaller */
  3858.  
  3859.     /*
  3860.      * Now make the other frames smaller.
  3861.      */
  3862.     while (fr != NULL && offset > 0)
  3863.     {
  3864.     n = frame_minheight(fr, NULL);
  3865.     if (fr->fr_height - offset <= n)
  3866.     {
  3867.         offset -= fr->fr_height - n;
  3868.         frame_new_height(fr, n, !up);
  3869.     }
  3870.     else
  3871.     {
  3872.         frame_new_height(fr, fr->fr_height - offset, !up);
  3873.         break;
  3874.     }
  3875.     if (up)
  3876.         fr = fr->fr_prev;
  3877.     else
  3878.         fr = fr->fr_next;
  3879.     }
  3880.     row = win_comp_pos();
  3881.     screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
  3882.     cmdline_row = row;
  3883.     p_ch = Rows - cmdline_row;
  3884.     if (p_ch < 1)
  3885.     p_ch = 1;
  3886.     redraw_all_later(NOT_VALID);
  3887.     showmode();
  3888. }
  3889.  
  3890. #ifdef FEAT_VERTSPLIT
  3891. /*
  3892.  * Separator line of curwin is dragged "offset" lines right (negative is left).
  3893.  */
  3894.     void
  3895. win_drag_vsep_line(offset)
  3896.     int        offset;
  3897. {
  3898.     frame_T    *curfr;
  3899.     frame_T    *fr;
  3900.     int        room;
  3901.     int        left;    /* if TRUE, drag separator line left, otherwise right */
  3902.     int        n;
  3903.  
  3904.     fr = curwin->w_frame;
  3905.     if (fr == topframe)        /* only one window (cannot happe?) */
  3906.     return;
  3907.     curfr = fr;
  3908.     fr = fr->fr_parent;
  3909.     /* When the parent frame is not a row of frames, its parent should be. */
  3910.     if (fr->fr_layout != FR_ROW)
  3911.     {
  3912.     if (fr == topframe)    /* only a column of windows (cannot happen?) */
  3913.         return;
  3914.     curfr = fr;
  3915.     fr = fr->fr_parent;
  3916.     }
  3917.  
  3918.     /* If this is the last frame in a row, may want to resize a parent
  3919.      * frame instead. */
  3920.     while (curfr->fr_next == NULL)
  3921.     {
  3922.     if (fr == topframe)
  3923.         break;
  3924.     curfr = fr;
  3925.     fr = fr->fr_parent;
  3926.     if (fr != topframe)
  3927.     {
  3928.         curfr = fr;
  3929.         fr = fr->fr_parent;
  3930.     }
  3931.     }
  3932.  
  3933.     if (offset < 0) /* drag left */
  3934.     {
  3935.     left = TRUE;
  3936.     offset = -offset;
  3937.     /* sum up the room of the current frame and left of it */
  3938.     room = 0;
  3939.     for (fr = fr->fr_child; ; fr = fr->fr_next)
  3940.     {
  3941.         room += fr->fr_width - frame_minwidth(fr, NULL);
  3942.         if (fr == curfr)
  3943.         break;
  3944.     }
  3945.     fr = curfr->fr_next;        /* put fr at frame that grows */
  3946.     }
  3947.     else    /* drag right */
  3948.     {
  3949.     left = FALSE;
  3950.     /* sum up the room of frames right of the current one */
  3951.     room = 0;
  3952.     for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
  3953.         room += fr->fr_width - frame_minwidth(fr, NULL);
  3954.     fr = curfr;            /* put fr at window that grows */
  3955.     }
  3956.  
  3957.     if (room < offset)        /* Not enough room */
  3958.     offset = room;        /* Move as far as we can */
  3959.     if (offset <= 0)        /* No room at all, quit. */
  3960.     return;
  3961.  
  3962.     /* grow frame fr by offset lines */
  3963.     frame_new_width(fr, fr->fr_width + offset, left);
  3964.  
  3965.     /* shrink other frames: current and at the left or at the right */
  3966.     if (left)
  3967.     fr = curfr;        /* current frame gets smaller */
  3968.     else
  3969.     fr = curfr->fr_next;    /* next frame gets smaller */
  3970.  
  3971.     while (fr != NULL && offset > 0)
  3972.     {
  3973.     n = frame_minwidth(fr, NULL);
  3974.     if (fr->fr_width - offset <= n)
  3975.     {
  3976.         offset -= fr->fr_width - n;
  3977.         frame_new_width(fr, n, !left);
  3978.     }
  3979.     else
  3980.     {
  3981.         frame_new_width(fr, fr->fr_width - offset, !left);
  3982.         break;
  3983.     }
  3984.     if (left)
  3985.         fr = fr->fr_prev;
  3986.     else
  3987.         fr = fr->fr_next;
  3988.     }
  3989.     (void)win_comp_pos();
  3990.     redraw_all_later(NOT_VALID);
  3991. }
  3992. #endif /* FEAT_VERTSPLIT */
  3993. #endif /* FEAT_MOUSE */
  3994.  
  3995. #endif /* FEAT_WINDOWS */
  3996.  
  3997. /*
  3998.  * Set the height of a window.
  3999.  * This takes care of the things inside the window, not what happens to the
  4000.  * window position, the frame or to other windows.
  4001.  */
  4002.     static void
  4003. win_new_height(wp, height)
  4004.     win_T    *wp;
  4005.     int        height;
  4006. {
  4007.     linenr_T    lnum;
  4008.     int        sline, line_size;
  4009. #define FRACTION_MULT    16384L
  4010.  
  4011.     /* Don't want a negative height.  Happens when splitting a tiny window.
  4012.      * Will equalize heights soon to fix it. */
  4013.     if (height < 0)
  4014.     height = 0;
  4015.  
  4016.     if (wp->w_wrow != wp->w_prev_fraction_row && wp->w_height > 0)
  4017.     wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
  4018.                     + FRACTION_MULT / 2) / (long)wp->w_height;
  4019.  
  4020.     wp->w_height = height;
  4021.     wp->w_skipcol = 0;
  4022.  
  4023. #ifdef FEAT_SCROLLBIND
  4024.     /* Don't set w_topline when 'scrollbind' is set and this isn't the current
  4025.      * window. */
  4026.     if (!wp->w_p_scb || wp == curwin)
  4027. #endif
  4028.     {
  4029.     lnum = wp->w_cursor.lnum;
  4030.     if (lnum < 1)        /* can happen when starting up */
  4031.         lnum = 1;
  4032.     wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
  4033.     line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
  4034.     sline = wp->w_wrow - line_size;
  4035.     if (sline < 0)
  4036.     {
  4037.         /*
  4038.          * Cursor line would go off top of screen if w_wrow was this high.
  4039.          */
  4040.         wp->w_wrow = line_size;
  4041.     }
  4042.     else
  4043.     {
  4044.         while (sline > 0 && lnum > 1)
  4045.         {
  4046. #ifdef FEAT_FOLDING
  4047.         hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
  4048. #endif
  4049.         --lnum;
  4050. #ifdef FEAT_DIFF
  4051.         if (lnum == wp->w_topline)
  4052.             line_size = plines_win_nofill(wp, lnum, TRUE)
  4053.                                   + wp->w_topfill;
  4054.         else
  4055. #endif
  4056.             line_size = plines_win(wp, lnum, TRUE);
  4057.         sline -= line_size;
  4058.         }
  4059.         if (sline < 0)
  4060.         {
  4061.         /*
  4062.          * Line we want at top would go off top of screen.  Use next
  4063.          * line instead.
  4064.          */
  4065. #ifdef FEAT_FOLDING
  4066.         hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
  4067. #endif
  4068.         lnum++;
  4069.         wp->w_wrow -= line_size + sline;
  4070.         }
  4071.         else if (sline > 0)
  4072.         {
  4073.         /* First line of file reached, use that as topline. */
  4074.         lnum = 1;
  4075.         wp->w_wrow -= sline;
  4076.         }
  4077.     }
  4078.     set_topline(wp, lnum);
  4079.     }
  4080.  
  4081.     if (wp == curwin)
  4082.     {
  4083.     if (p_so)
  4084.         update_topline();
  4085.     curs_columns(FALSE);    /* validate w_wrow */
  4086.     }
  4087.     wp->w_prev_fraction_row = wp->w_wrow;
  4088.  
  4089.     win_comp_scroll(wp);
  4090.     redraw_win_later(wp, NOT_VALID);
  4091. #ifdef FEAT_WINDOWS
  4092.     wp->w_redr_status = TRUE;
  4093. #endif
  4094.     invalidate_botline_win(wp);
  4095. }
  4096.  
  4097. #ifdef FEAT_VERTSPLIT
  4098. /*
  4099.  * Set the width of a window.
  4100.  */
  4101.     static void
  4102. win_new_width(wp, width)
  4103.     win_T    *wp;
  4104.     int        width;
  4105. {
  4106.     wp->w_width = width;
  4107.     wp->w_lines_valid = 0;
  4108.     changed_line_abv_curs_win(wp);
  4109.     invalidate_botline_win(wp);
  4110.     if (wp == curwin)
  4111.     {
  4112.     update_topline();
  4113.     curs_columns(TRUE);    /* validate w_wrow */
  4114.     }
  4115.     redraw_win_later(wp, NOT_VALID);
  4116.     wp->w_redr_status = TRUE;
  4117. }
  4118. #endif
  4119.  
  4120.     void
  4121. win_comp_scroll(wp)
  4122.     win_T    *wp;
  4123. {
  4124.     wp->w_p_scr = ((unsigned)wp->w_height >> 1);
  4125.     if (wp->w_p_scr == 0)
  4126.     wp->w_p_scr = 1;
  4127. }
  4128.  
  4129. /*
  4130.  * command_height: called whenever p_ch has been changed
  4131.  */
  4132.     void
  4133. command_height(old_p_ch)
  4134.     long    old_p_ch;
  4135. {
  4136. #ifdef FEAT_WINDOWS
  4137.     int        h;
  4138.     frame_T    *frp;
  4139.  
  4140.     /* Find bottom frame with width of screen. */
  4141.     frp = lastwin->w_frame;
  4142. #ifdef FEAT_VERTSPLIT
  4143.     while (frp->fr_width != Columns && frp->fr_parent != NULL)
  4144.     frp = frp->fr_parent;
  4145. #endif
  4146.  
  4147.     if (starting != NO_SCREEN)
  4148.     {
  4149.     cmdline_row = Rows - p_ch;
  4150.  
  4151.     if (p_ch > old_p_ch)            /* p_ch got bigger */
  4152.     {
  4153.         while (p_ch > old_p_ch)
  4154.         {
  4155.         if (frp == NULL)
  4156.         {
  4157.             EMSG(_(e_noroom));
  4158.             p_ch = old_p_ch;
  4159.             cmdline_row = Rows - p_ch;
  4160.             break;
  4161.         }
  4162.         h = frp->fr_height - frame_minheight(frp, NULL);
  4163.         if (h > p_ch - old_p_ch)
  4164.             h = p_ch - old_p_ch;
  4165.         old_p_ch += h;
  4166.         frame_add_height(frp, -h);
  4167.         frp = frp->fr_prev;
  4168.         }
  4169.  
  4170.         /* Recompute window positions. */
  4171.         (void)win_comp_pos();
  4172.  
  4173.         /* clear the lines added to cmdline */
  4174.         if (full_screen)
  4175.         screen_fill((int)(cmdline_row), (int)Rows, 0,
  4176.                            (int)Columns, ' ', ' ', 0);
  4177.         msg_row = cmdline_row;
  4178.         redraw_cmdline = TRUE;
  4179.         return;
  4180.     }
  4181.  
  4182.     if (msg_row < cmdline_row)
  4183.         msg_row = cmdline_row;
  4184.     redraw_cmdline = TRUE;
  4185.     }
  4186.     frame_add_height(frp, (int)(old_p_ch - p_ch));
  4187. #else
  4188.     win_setheight((int)(firstwin->w_height + old_p_ch - p_ch));
  4189.     cmdline_row = Rows - p_ch;
  4190. #endif
  4191. }
  4192.  
  4193. #if defined(FEAT_WINDOWS) || defined(PROTO)
  4194. /*
  4195.  * Resize frame "frp" to be "n" lines higher (negative for less high).
  4196.  * Also resize the frames it is contained in.
  4197.  */
  4198.     static void
  4199. frame_add_height(frp, n)
  4200.     frame_T    *frp;
  4201.     int        n;
  4202. {
  4203.     frame_new_height(frp, frp->fr_height + n, FALSE);
  4204.     for (;;)
  4205.     {
  4206.     frp = frp->fr_parent;
  4207.     if (frp == NULL)
  4208.         break;
  4209.     frp->fr_height += n;
  4210.     }
  4211. }
  4212.  
  4213. /*
  4214.  * Add or remove a status line for the bottom window(s), according to the
  4215.  * value of 'laststatus'.
  4216.  */
  4217.     void
  4218. last_status(morewin)
  4219.     int        morewin;    /* pretend there are two or more windows */
  4220. {
  4221.     /* Don't make a difference between horizontal or vertical split. */
  4222.     last_status_rec(topframe, (p_ls == 2
  4223.               || (p_ls == 1 && (morewin || lastwin != firstwin))));
  4224. }
  4225.  
  4226.     static void
  4227. last_status_rec(fr, statusline)
  4228.     frame_T    *fr;
  4229.     int        statusline;
  4230. {
  4231.     frame_T    *fp;
  4232.     win_T    *wp;
  4233.  
  4234.     if (fr->fr_layout == FR_LEAF)
  4235.     {
  4236.     wp = fr->fr_win;
  4237.     if (wp->w_status_height != 0 && !statusline)
  4238.     {
  4239.         /* remove status line */
  4240.         win_new_height(wp, wp->w_height + 1);
  4241.         wp->w_status_height = 0;
  4242.         comp_col();
  4243.     }
  4244.     else if (wp->w_status_height == 0 && statusline)
  4245.     {
  4246.         /* Find a frame to take a line from. */
  4247.         fp = fr;
  4248.         while (fp->fr_height <= frame_minheight(fp, NULL))
  4249.         {
  4250.         if (fp == topframe)
  4251.         {
  4252.             EMSG(_(e_noroom));
  4253.             return;
  4254.         }
  4255.         /* In a column of frames: go to frame above.  If already at
  4256.          * the top or in a row of frames: go to parent. */
  4257.         if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
  4258.             fp = fp->fr_prev;
  4259.         else
  4260.             fp = fp->fr_parent;
  4261.         }
  4262.         wp->w_status_height = 1;
  4263.         if (fp != fr)
  4264.         {
  4265.         frame_new_height(fp, fp->fr_height - 1, FALSE);
  4266.         frame_fix_height(wp);
  4267.         (void)win_comp_pos();
  4268.         }
  4269.         else
  4270.         win_new_height(wp, wp->w_height - 1);
  4271.         comp_col();
  4272.         redraw_all_later(NOT_VALID);
  4273.     }
  4274.     }
  4275. #ifdef FEAT_VERTSPLIT
  4276.     else if (fr->fr_layout == FR_ROW)
  4277.     {
  4278.     /* vertically split windows, set status line for each one */
  4279.     for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
  4280.         last_status_rec(fp, statusline);
  4281.     }
  4282. #endif
  4283.     else
  4284.     {
  4285.     /* horizontally split window, set status line for last one */
  4286.     for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
  4287.         ;
  4288.     last_status_rec(fp, statusline);
  4289.     }
  4290. }
  4291.  
  4292. #endif /* FEAT_WINDOWS */
  4293.  
  4294. #if defined(FEAT_SEARCHPATH) || defined(PROTO)
  4295. /*
  4296.  * Return the file name under or after the cursor.
  4297.  *
  4298.  * The 'path' option is searched if the file name is not absolute.
  4299.  * The string returned has been alloc'ed and should be freed by the caller.
  4300.  * NULL is returned if the file name or file is not found.
  4301.  *
  4302.  * options:
  4303.  * FNAME_MESS        give error messages
  4304.  * FNAME_EXP        expand to path
  4305.  * FNAME_HYP        check for hypertext link
  4306.  * FNAME_INCL        apply "includeexpr"
  4307.  */
  4308.     char_u *
  4309. file_name_at_cursor(options, count)
  4310.     int        options;
  4311.     long    count;
  4312. {
  4313.     return file_name_in_line(ml_get_curline(),
  4314.               curwin->w_cursor.col, options, count, curbuf->b_ffname);
  4315. }
  4316.  
  4317. /*
  4318.  * Return the name of the file under or after ptr[col].
  4319.  * Otherwise like file_name_at_cursor().
  4320.  */
  4321.     char_u *
  4322. file_name_in_line(line, col, options, count, rel_fname)
  4323.     char_u    *line;
  4324.     int        col;
  4325.     int        options;
  4326.     long    count;
  4327.     char_u    *rel_fname;    /* file we are searching relative to */
  4328. {
  4329.     char_u    *ptr;
  4330.     int        len;
  4331.  
  4332.     /*
  4333.      * search forward for what could be the start of a file name
  4334.      */
  4335.     ptr = line + col;
  4336.     while (*ptr != NUL && !vim_isfilec(*ptr))
  4337.     ++ptr;
  4338.     if (*ptr == NUL)        /* nothing found */
  4339.     {
  4340.     if (options & FNAME_MESS)
  4341.         EMSG(_("E446: No file name under cursor"));
  4342.     return NULL;
  4343.     }
  4344.  
  4345.     /*
  4346.      * Search backward for first char of the file name.
  4347.      * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
  4348.      */
  4349.     while (ptr > line)
  4350.     {
  4351. #ifdef FEAT_MBYTE
  4352.     if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
  4353.         ptr -= len + 1;
  4354.     else
  4355. #endif
  4356.     if (vim_isfilec(ptr[-1])
  4357.         || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
  4358.         --ptr;
  4359.     else
  4360.         break;
  4361.     }
  4362.  
  4363.     /*
  4364.      * Search forward for the last char of the file name.
  4365.      * Also allow "://" when ':' is not in 'isfname'.
  4366.      */
  4367.     len = 0;
  4368.     while (vim_isfilec(ptr[len])
  4369.              || ((options & FNAME_HYP) && path_is_url(ptr + len)))
  4370. #ifdef FEAT_MBYTE
  4371.     if (has_mbyte)
  4372.         len += (*mb_ptr2len_check)(ptr + len);
  4373.     else
  4374. #endif
  4375.         ++len;
  4376.  
  4377.     /*
  4378.      * If there is trailing punctuation, remove it.
  4379.      * But don't remove "..", could be a directory name.
  4380.      */
  4381.     if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
  4382.                                && ptr[len - 2] != '.')
  4383.     --len;
  4384.  
  4385.     return find_file_name_in_path(ptr, len, options, count, rel_fname);
  4386. }
  4387.  
  4388. # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
  4389. static char_u *eval_includeexpr __ARGS((char_u *ptr, int len));
  4390.  
  4391.     static char_u *
  4392. eval_includeexpr(ptr, len)
  4393.     char_u    *ptr;
  4394.     int        len;
  4395. {
  4396.     char_u    *res;
  4397.  
  4398.     set_vim_var_string(VV_FNAME, ptr, len);
  4399.     res = eval_to_string_safe(curbuf->b_p_inex, NULL);
  4400.     set_vim_var_string(VV_FNAME, NULL, 0);
  4401.     return res;
  4402. }
  4403. #endif
  4404.  
  4405. /*
  4406.  * Return the name of the file ptr[len] in 'path'.
  4407.  * Otherwise like file_name_at_cursor().
  4408.  */
  4409.     char_u *
  4410. find_file_name_in_path(ptr, len, options, count, rel_fname)
  4411.     char_u    *ptr;
  4412.     int        len;
  4413.     int        options;
  4414.     long    count;
  4415.     char_u    *rel_fname;    /* file we are searching relative to */
  4416. {
  4417.     char_u    *file_name;
  4418.     int        c;
  4419. # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
  4420.     char_u    *tofree = NULL;
  4421.  
  4422.     if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
  4423.     {
  4424.     tofree = eval_includeexpr(ptr, len);
  4425.     if (tofree != NULL)
  4426.     {
  4427.         ptr = tofree;
  4428.         len = (int)STRLEN(ptr);
  4429.     }
  4430.     }
  4431. # endif
  4432.  
  4433.     if (options & FNAME_EXP)
  4434.     {
  4435.     file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
  4436.                                  TRUE, rel_fname);
  4437.  
  4438. # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
  4439.     /*
  4440.      * If the file could not be found in a normal way, try applying
  4441.      * 'includeexpr' (unless done already).
  4442.      */
  4443.     if (file_name == NULL
  4444.         && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
  4445.     {
  4446.         tofree = eval_includeexpr(ptr, len);
  4447.         if (tofree != NULL)
  4448.         {
  4449.         ptr = tofree;
  4450.         len = (int)STRLEN(ptr);
  4451.         file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
  4452.                                  TRUE, rel_fname);
  4453.         }
  4454.     }
  4455. # endif
  4456.     if (file_name == NULL && (options & FNAME_MESS))
  4457.     {
  4458.         c = ptr[len];
  4459.         ptr[len] = NUL;
  4460.         EMSG2(_("E447: Can't find file \"%s\" in path"), ptr);
  4461.         ptr[len] = c;
  4462.     }
  4463.  
  4464.     /* Repeat finding the file "count" times.  This matters when it
  4465.      * appears several times in the path. */
  4466.     while (file_name != NULL && --count > 0)
  4467.     {
  4468.         vim_free(file_name);
  4469.         file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
  4470.     }
  4471.     }
  4472.     else
  4473.     file_name = vim_strnsave(ptr, len);
  4474.  
  4475. # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
  4476.     vim_free(tofree);
  4477. # endif
  4478.  
  4479.     return file_name;
  4480. }
  4481. #endif /* FEAT_SEARCHPATH */
  4482.  
  4483. /*
  4484.  * Check if the "://" of a URL is at the pointer, return URL_SLASH.
  4485.  * Also check for ":\\", which MS Internet Explorer accepts, return
  4486.  * URL_BACKSLASH.
  4487.  */
  4488.     static int
  4489. path_is_url(p)
  4490.     char_u  *p;
  4491. {
  4492.     if (STRNCMP(p, "://", (size_t)3) == 0)
  4493.     return URL_SLASH;
  4494.     else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
  4495.     return URL_BACKSLASH;
  4496.     return 0;
  4497. }
  4498.  
  4499. /*
  4500.  * Check if "fname" starts with "name://".  Return URL_SLASH if it does.
  4501.  * Return URL_BACKSLASH for "name:\\".
  4502.  * Return zero otherwise.
  4503.  */
  4504.     int
  4505. path_with_url(fname)
  4506.     char_u *fname;
  4507. {
  4508.     char_u *p;
  4509.  
  4510.     for (p = fname; isalpha(*p); ++p)
  4511.     ;
  4512.     return path_is_url(p);
  4513. }
  4514.  
  4515. /*
  4516.  * Return TRUE if "name" is a full (absolute) path name or URL.
  4517.  */
  4518.     int
  4519. vim_isAbsName(name)
  4520.     char_u    *name;
  4521. {
  4522.     return (path_with_url(name) != 0 || mch_isFullName(name));
  4523. }
  4524.  
  4525. /*
  4526.  * Get absolute file name into buffer 'buf' of length 'len' bytes.
  4527.  *
  4528.  * return FAIL for failure, OK otherwise
  4529.  */
  4530.     int
  4531. vim_FullName(fname, buf, len, force)
  4532.     char_u    *fname, *buf;
  4533.     int        len;
  4534.     int        force;
  4535. {
  4536.     int        retval = OK;
  4537.     int        url;
  4538.  
  4539.     *buf = NUL;
  4540.     if (fname == NULL)
  4541.     return FAIL;
  4542.  
  4543.     url = path_with_url(fname);
  4544.     if (!url)
  4545.     retval = mch_FullName(fname, buf, len, force);
  4546.     if (url || retval == FAIL)
  4547.     {
  4548.     /* something failed; use the file name (truncate when too long) */
  4549.     STRNCPY(buf, fname, len);
  4550.     buf[len - 1] = NUL;
  4551.     }
  4552. #if defined(MACOS_CLASSIC) || defined(OS2) || defined(MSDOS) || defined(MSWIN)
  4553.     slash_adjust(buf);
  4554. #endif
  4555.     return retval;
  4556. }
  4557.  
  4558. /*
  4559.  * Return the minimal number of rows that is needed on the screen to display
  4560.  * the current number of windows.
  4561.  */
  4562.     int
  4563. min_rows()
  4564. {
  4565. #ifdef FEAT_WINDOWS
  4566.     win_T    *wp;
  4567. #endif
  4568.     int        total;
  4569.  
  4570.     if (firstwin == NULL)    /* not initialized yet */
  4571.     return MIN_LINES;
  4572.  
  4573.     total = 1;        /* count the room for the command line */
  4574. #ifdef FEAT_WINDOWS
  4575.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  4576.     total += p_wmh + W_STATUS_HEIGHT(wp);
  4577.     if (p_wmh == 0)
  4578. #endif
  4579.     total += 1;    /* at least one window should have a line! */
  4580.     return total;
  4581. }
  4582.  
  4583. /*
  4584.  * Return TRUE if there is only one window, not counting a help or preview
  4585.  * window, unless it is the current window.
  4586.  */
  4587.     int
  4588. only_one_window()
  4589. {
  4590. #ifdef FEAT_WINDOWS
  4591.     int        count = 0;
  4592.     win_T    *wp;
  4593.  
  4594.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  4595.     if (!(wp->w_buffer->b_help
  4596. # ifdef FEAT_QUICKFIX
  4597.             || wp->w_p_pvw
  4598. # endif
  4599.          ) || wp == curwin)
  4600.         ++count;
  4601.     return (count <= 1);
  4602. #else
  4603.     return TRUE;
  4604. #endif
  4605. }
  4606.  
  4607. #if defined(FEAT_WINDOWS) || defined(FEAT_AUTOCMD) || defined(PROTO)
  4608. /*
  4609.  * Correct the cursor line number in other windows.  Used after changing the
  4610.  * current buffer, and before applying autocommands.
  4611.  * When "do_curwin" is TRUE, also check current window.
  4612.  */
  4613.     void
  4614. check_lnums(do_curwin)
  4615.     int        do_curwin;
  4616. {
  4617.     win_T    *wp;
  4618.  
  4619. #ifdef FEAT_WINDOWS
  4620.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  4621.     if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
  4622. #else
  4623.     wp = curwin;
  4624.     if (do_curwin)
  4625. #endif
  4626.     {
  4627.         if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  4628.         wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  4629.         if (wp->w_topline > curbuf->b_ml.ml_line_count)
  4630.         wp->w_topline = curbuf->b_ml.ml_line_count;
  4631.     }
  4632. }
  4633. #endif
  4634.  
  4635. #if defined(FEAT_WINDOWS) || defined(PROTO)
  4636.  
  4637. /*
  4638.  * A snapshot of the window sizes, to restore them after closing the help
  4639.  * window.
  4640.  * Only these fields are used:
  4641.  * fr_layout
  4642.  * fr_width
  4643.  * fr_height
  4644.  * fr_next
  4645.  * fr_child
  4646.  * fr_win (only valid for the old curwin, NULL otherwise)
  4647.  */
  4648. static frame_T *snapshot = NULL;
  4649.  
  4650. /*
  4651.  * Create a snapshot of the current frame sizes.
  4652.  */
  4653.     static void
  4654. make_snapshot()
  4655. {
  4656.     clear_snapshot();
  4657.     make_snapshot_rec(topframe, &snapshot);
  4658. }
  4659.  
  4660.     static void
  4661. make_snapshot_rec(fr, frp)
  4662.     frame_T    *fr;
  4663.     frame_T    **frp;
  4664. {
  4665.     *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
  4666.     if (*frp == NULL)
  4667.     return;
  4668.     (*frp)->fr_layout = fr->fr_layout;
  4669. # ifdef FEAT_VERTSPLIT
  4670.     (*frp)->fr_width = fr->fr_width;
  4671. # endif
  4672.     (*frp)->fr_height = fr->fr_height;
  4673.     if (fr->fr_next != NULL)
  4674.     make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
  4675.     if (fr->fr_child != NULL)
  4676.     make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
  4677.     if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
  4678.     (*frp)->fr_win = curwin;
  4679. }
  4680.  
  4681. /*
  4682.  * Remove any existing snapshot.
  4683.  */
  4684.     static void
  4685. clear_snapshot()
  4686. {
  4687.     clear_snapshot_rec(snapshot);
  4688.     snapshot = NULL;
  4689. }
  4690.  
  4691.     static void
  4692. clear_snapshot_rec(fr)
  4693.     frame_T    *fr;
  4694. {
  4695.     if (fr != NULL)
  4696.     {
  4697.     clear_snapshot_rec(fr->fr_next);
  4698.     clear_snapshot_rec(fr->fr_child);
  4699.     vim_free(fr);
  4700.     }
  4701. }
  4702.  
  4703. /*
  4704.  * Restore a previously created snapshot, if there is any.
  4705.  * This is only done if the screen size didn't change and the window layout is
  4706.  * still the same.
  4707.  */
  4708.     static void
  4709. restore_snapshot(close_curwin)
  4710.     int        close_curwin;        /* closing current window */
  4711. {
  4712.     win_T    *wp;
  4713.  
  4714.     if (snapshot != NULL
  4715. # ifdef FEAT_VERTSPLIT
  4716.         && snapshot->fr_width == topframe->fr_width
  4717. # endif
  4718.         && snapshot->fr_height == topframe->fr_height
  4719.         && check_snapshot_rec(snapshot, topframe) == OK)
  4720.     {
  4721.     wp = restore_snapshot_rec(snapshot, topframe);
  4722.     win_comp_pos();
  4723.     if (wp != NULL && close_curwin)
  4724.         win_goto(wp);
  4725.     redraw_all_later(CLEAR);
  4726.     }
  4727.     clear_snapshot();
  4728. }
  4729.  
  4730. /*
  4731.  * Check if frames "sn" and "fr" have the same layout, same following frames
  4732.  * and same children.
  4733.  */
  4734.     static int
  4735. check_snapshot_rec(sn, fr)
  4736.     frame_T    *sn;
  4737.     frame_T    *fr;
  4738. {
  4739.     if (sn->fr_layout != fr->fr_layout
  4740.         || (sn->fr_next == NULL) != (fr->fr_next == NULL)
  4741.         || (sn->fr_child == NULL) != (fr->fr_child == NULL)
  4742.         || (sn->fr_next != NULL
  4743.         && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
  4744.         || (sn->fr_child != NULL
  4745.         && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL))
  4746.     return FAIL;
  4747.     return OK;
  4748. }
  4749.  
  4750. /*
  4751.  * Copy the size of snapshot frame "sn" to frame "fr".  Do the same for all
  4752.  * following frames and children.
  4753.  * Returns a pointer to the old current window, or NULL.
  4754.  */
  4755.     static win_T *
  4756. restore_snapshot_rec(sn, fr)
  4757.     frame_T    *sn;
  4758.     frame_T    *fr;
  4759. {
  4760.     win_T    *wp = NULL;
  4761.     win_T    *wp2;
  4762.  
  4763.     fr->fr_height = sn->fr_height;
  4764. # ifdef FEAT_VERTSPLIT
  4765.     fr->fr_width = sn->fr_width;
  4766. # endif
  4767.     if (fr->fr_layout == FR_LEAF)
  4768.     {
  4769.     frame_new_height(fr, fr->fr_height, FALSE);
  4770. # ifdef FEAT_VERTSPLIT
  4771.     frame_new_width(fr, fr->fr_width, FALSE);
  4772. # endif
  4773.     wp = sn->fr_win;
  4774.     }
  4775.     if (sn->fr_next != NULL)
  4776.     {
  4777.     wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
  4778.     if (wp2 != NULL)
  4779.         wp = wp2;
  4780.     }
  4781.     if (sn->fr_child != NULL)
  4782.     {
  4783.     wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
  4784.     if (wp2 != NULL)
  4785.         wp = wp2;
  4786.     }
  4787.     return wp;
  4788. }
  4789.  
  4790. #endif
  4791.  
  4792. #if (defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)) || defined(PROTO)
  4793. /*
  4794.  * Return TRUE if there is any vertically split window.
  4795.  */
  4796.     int
  4797. win_hasvertsplit()
  4798. {
  4799.     frame_T    *fr;
  4800.  
  4801.     if (topframe->fr_layout == FR_ROW)
  4802.     return TRUE;
  4803.  
  4804.     if (topframe->fr_layout == FR_COL)
  4805.     for (fr = topframe->fr_child; fr != NULL; fr = fr->fr_next)
  4806.         if (fr->fr_layout == FR_ROW)
  4807.         return TRUE;
  4808.  
  4809.     return FALSE;
  4810. }
  4811. #endif
  4812.